service-name="updateSurvey"/> <field use-when="survey!=null" name="surveyId" ... /> ... <field name="isAnonymous"> <drop-down no-current-selected-key="N" allow-empty="false"> <option key="Y"/><option key="N"/> </drop-down> </field> ... <field name="submitButton" title="${uiLabelMap.CommonUpdate}" widget-style="smallSubmit"> <submit button-type="button"/> </field> </form> The create survey example, as described here, is implemented using models in three different languages. The complete implementation actually involves even more languages such as a Screen DSL to specify the layout of the screen where the form is placed, and a Minilang DSL which is a data-manipulation language used to implement the service. However, these three languages do illustrate the main idea of making each concern concrete. The example also shows a simple way of reducing redundancy by letting the languages overlap slightly. Multi-level customization Domain-specific languages, like those described above, have limited expressiveness. It is often necessary to add code snippets in a general-purpose language like Java to implement specialized functionality that is beyond the scope of the languages. This method is called multi-level customization. Since this method is very commonly used in setups with multiple languages, we will illustrate it by a continuation of the example. Let us call this the build PDF example. Suppose we want to build a PDF file for each survey response to the online surveys that users create. Building a PDF file is outside the scope of our languages so we need to write some Java code that can invoke a third-party PDF library to perform this specialized functionality. Two artifacts are required: First, an additional service model, as shown below, in the Service DSL that defines the interface of the concrete service such that it can be accessed on the modeling level. The service model describes the location of the implementation and what the input and output attributes are. <service name="buildPdfFromSurveyResponse" engine="java" location="org.ofbiz.content.survey.PdfSurveyServices" invoke="buildPdfFromSurveyResponse"> <attribute name="surveyResponseId" mode="IN" optional="false" .../> <attribute name="outByteWrapper" mode="OUT" optional="false" .../> </service> Second, we need a code snippet, as shown below, that contains the actual implementation of this service. A service can have multiple inputs and outputs so input to the Java method is a map, called context, from argument names to argument values and returns output in the form of another map, called results. public static Map buildPdfFromSurveyResponse (DispatchContext dctx , Map context) { String id = (String) context.get("surveyResponseId"); Map results = new HashMap(); try { // ...the response is retrieved from the database... // ...a pdf is built from the response... // ...the pdf is serialized as a bytearray... ByteWrapper