Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Step - 2 : Create the ofbiz-component.xml file on path hot-deploy/practice and place following content in it (for reference you can check this file in any other component of OFBiz):

Code Block
<?xml version="1.0" encoding="UTF-8"?>
<ofbiz-component name="practice"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:noNamespaceSchemaLocation="http://ofbiz.apache.org/dtds/ofbiz-component.xsd">
      <resource-loader 	name="main" type="component"/>
    <webapp name="practice"
       title="Practice"
       server="default-server"
       base-permission="OFBTOOLS"
       location="webapp/practice"
       mount-point="/practice"
       app-bar-display="false"/>
</ofbiz-component>

...

2. Here 'resource-loader name' can be any string here it is "main". The 'type' tells OFBiz that we will be loading a component.

Code Block

 <resource-loader 	name="main" type="component"/>

 3. In <webapp> tag, we have different attributes and their purpose is as follows:

Code Block

 <webapp name="practice"
       title="Practice"
       server="default-server"
       base-permission="OFBTOOLS"
       location="webapp/practice"
       mount-point="/practice"
       app-bar-display="false"/>

a) name :- defines the name of our web application.
b) title :- This will be the title of our component
c) server :- This will let OFBiz know what server to use
d) base-permission :- This a) name :- defines the name of our web application.
b) title :- This will be the title of our component
c) server :- This will let OFBiz know what server to use
d) base-permission :- This line requires that the user should have the OFBTOOLS permission to be able to use the application. Since the 'admin' user has this permission we do not have to create any new users.
e) location :- This will be the location that is the default base directory for the server
f) mount-point :- This is the URL used to access this resource. in this case it would be localhost:8080/practice
g) app-bar-display :- This will let OFBiz know if we want our component to show up in the main application tabs that are part of the common ofbiz decorator. 

...

Step - 4 Create a file named "web.xml"(web.xml follows j2ee webapp specs). Contents of this file can be taken from any of the existing component e.g. example component. The Important values to change are the <display-name>, the localDispatcherName, and the mainDecoratorLocation.

Code Block

<context-param>
        <param-name>localDispatcherName</param-name>
        <param-value>practice</param-value>
        <description>A unique name used to identify/recognize the local dispatcher for the Service Engine</description>
    </context-param>   
  
    <context-param>
        <param-name>mainDecoratorLocation</param-name>
        <param-value>component://practice/widget/CommonScreens.xml</param-value>
        <description>The location of the main-decorator screen to use for this webapp; referred to as a context variable in screen def XML files.</description>
    </context-param>


For now put the value: "component://practice/widget/CommonScreens.xml" in for the location and you will see why in a while. This location is used in pointing to the main decorator location in screens like

Code Block
${parameters.mainDecoratorLocation}

. Which increases the code Independence from changing the path at many places when we need to change the main decorator location. At that time we just need to change the location there only and will work for all the screens where it has been used. One more advantage of doing this in screens is the purpose of resuability of existing screens which we can use from other components, but it decorate that screen by your decorator only as the same pattern is used at all the places and in all the components to show the mainDecoratorLocation. Concentrate on this when you add decorators in your screens in not too distant future with the development of this application.

Step - 5 Create a file named "controller.xml" (used by ofbiz webapp controller)  This file will be small and simple at first but will grow as we add functionality later on. For now insert the following code:

Code Block
<?xml version="1.0" encoding="UTF-8"?>
<site-conf xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:noNamespaceSchemaLocation="http://ofbiz.apache.org/dtds/site-conf.xsd">

       <include location="component://common/webcommon/WEB-INF/common-controller.xml"/>
       <description>Practice Component Site Configuration File</description>
       <owner>Copyright 2001-2008 The Apache Software Foundation</owner>

       <!-- Request Mappings -->

       <request-map uri="main">
           <security https="false" auth="false"/>
           <response name="success" type="view" value="main"/>
       </request-map>

       <!-- end of request mappings -->

       <!-- View Mappings -->

       <view-map name="main" type="screen" page="component://practice/widget/PracticeScreens.xml#main"/>

       <!-- end of view mappings -->

</site-conf>

...

All these readings will be really of help.
Very first screen will be like :

Code Block
<?xml version="1.0" encoding="UTF-8"?>

<screens xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:noNamespaceSchemaLocation="http://ofbiz.apache.org/dtds/widget-screen.xsd">

    <screen name="main">
        <section>
            <widgets>
                <label text="This is first practice"/>
            </widgets>
        </section>
    </screen>

</screens>

...

Step - 3: Create the sub-directory "actions" inside the WEB-INF directory.
In this directory we will create the scripting files. Scripting files are used to prepare data on fly. These files will be groovy files. Earlier we were using bsh(beanshell) files. This is a script which is used to fetch the data from database on the fly for the UI.
Reference : Tips & Tricks while working with Groovy & http://groovy.codehaus.org/. While working in groovy always be conscious about the imported classes and packages. Import only those which have been used in your file. For putting log messages use methods from "Debug" class just do this practice from the beginning itself. So create a file by name Person.groovy in this actions directory which will be fetching all the records from the entity "Person". At this moment this is really going to be the small code for doing this (a single line) like

Code Block
context.persons = delegator.findList("Person", null, null, null, null, false);

...

Step - 4 : Now in webapp "practice" create one ftl file by name "Person.ftl" which will be used to show the data fetched by groovy file.
Reference : http://freemarker.sourceforge.net/docs/
At this moment you need only to iterate the list of persons which is there in the context. The only code that is needed to that is:

Code Block
<#if persons?has_content>
  <h2>Some of the people who visited our site are:</h2>
  <br>
  <ul>
    <#list persons as person>
      <li>${person.firstName?if_exists} ${person.lastName?if_exists}<li>
    </#list>
  </ul>
</#if>

...

Note: -Here remember to create an entry for the config directory in your ofbiz-component.xml file.

which will be :

Code Block
<classpath type="dir" location="config"/>

...

Step - 1 :  Take reference from ExampleMenus.xml file for having login and logout options in your menu.
Targets for these options will be available from "component://common/webcommon/WEB-INF/common-controller.xml", which we have to include in our controller.xml.
or you can do these entries in your controller.xml file under

Code Block
<!- Request Mappings ->
<!-- Security Mappings -->
 <request-map uri="checkLogin" edit="false">
    <description>Verify a user is logged in.</description>
        <security https="true" auth="false"/>
        <event type="java" path="org.ofbiz.webapp.control.LoginWorker" invoke="checkLogin" />
        <response name="success" type="view" value="main"/>
        <response name="error" type="view" value="login"/>
    </request-map>

    <request-map uri="login">
        <security https="true" auth="false"/>
        <event type="java" path="org.ofbiz.webapp.control.LoginWorker" invoke="login"/>
        <response name="success" type="view" value="main"/>
        <response name="error" type="view" value="login"/>
    </request-map>

    <request-map uri="logout">
        <security https="true" auth="true"/>
        <event type="java" path="org.ofbiz.webapp.control.LoginWorker" invoke="logout"/>
        <response name="success" type="request" value="checkLogin"/>
        <response name="error" type="view" value="main"/>
    </request-map>

...

These requests are needed to add in your controller only when you have not included any of the other component controller which consist of these requests. So if you have already included common-controller.xml file then you don't need to explicitly do these entries in your controller.    
and the same view we have in place can be used for which we have entry in common-controller.xml file we can also have our own:

Code Block
<view-map name="login" type="screen" page="component://common/widget/CommonScreens.xml#login"/>

...

*Step - 2 :*In controller you have to create an entry for the request for the execution of a service and set the response like

Code Block
<request-map uri="createPracticePerson">
    <security https="true" auth="true"/>
    <event type="service" invoke="createPracticePerson"/>
    <response name="success" type="view" value="PersonForm"/>
</request-map>

...

This new feature enables you to just define the services by mentioning the operation you want to perform.Basically just set the engine attribute to "entity-auto" and the invoke attribute to "create", "update", or "delete".
like you can take a look in the following code from services.xml of example component:  

Code Block
<service name="createExample" default-entity-name="Example" engine="entity-auto" invoke="create" auth="true">
    <description>Create a Example</description>
    <permission-service service-name="exampleGenericPermission" main-action="CREATE"/>
    <auto-attributes include="pk" mode="OUT" optional="false"/>
    <auto-attributes include="nonpk" mode="IN" optional="true"/>
    <override name="exampleTypeId" optional="false"/>
    <override name="statusId" optional="false"/>
    <override name="exampleName" optional="false"/>
</service>

...

Here important thing to note is in case of simple event controller entry will be like :

Code Block
<request-map uri="createPracticePersonSimpleEvent">
    <security https="true" auth="true"/>{color}
    <event type="simple" path="org/hotwax/practice/PracticeEvents.xml" invoke="createPracticePersonSimpleEvent"/>
    <response name="success" type="view" value="CreatePracPersonSimpleEvent"/>
    <response name="error" type="view" value="CreatePracPersonSimpleEvent"/>
</request-map>

...

Here the path is the path of the file where the event is written. it will be practice/script/org/hotwax/practice.
and for java event controller entry will be like:

Code Block
<request-map uri="createPracticePersonJavaEvent">
    <security https="true" auth="true"/>
    <event type="java" path="org.hotwax.practice.PracticeEvents" invoke="createPracticePersonJavaEvent"/>
    <response name="success" type="view" value="CreatePracPersonJavaEvent"/>
    <response name="error" type="view" value="CreatePracPersonJavaEvent"/>
</request-map>

...

7.a : Process fields coming from the form like: 

Code Block
<call-map-processor in-map-name="parameters" out-map-name="createPersonContext">
    <simple-map-processor name="createPersonMap">
        <process field="firstName">
            <copy/>
            <not-empty>
                <fail-property property="PracticeFirstNameMissingError" resource="PracticeUiLabels"/>
            </not-empty>&nbsp;&nbsp;&nbsp;
        </process>
    </simple-map-processor>
</call-map-processor>
<check-errors/>

...

Step - 1 : The contents will be :

Code Block
public static String createPracticePersonJavaEvent(HttpServletRequest request, HttpServletResponse response){
    LocalDispatcher dispatcher = (LocalDispatcher) request.getAttribute("dispatcher");
    GenericDelegator delegator = (GenericDelegator) request.getAttribute("delegator");
}

...

Step - 2 : Now you have to process the fields comming from the form like

Code Block
String salutation = (String) request.getParameter("salutation");
String firstName = (String) request.getParameter("firstName");

...

Step - 3 : Now prepare a map for the values which you have to pass to the service which you will call "createPracticePerson" . Like

Code Block
Map createPersonCtx = UtilMisc.toMap("salutation", salutation, "firstName", firstName);

...

Step - 4 : Then at the end just call the service "createPracticePerson" like

Code Block
try{
    Map person = dispatcher.runSync("createPracticePerson", createPersonCtx);
 }catch (GenericServiceException e){
     Debug.logError(e.toString(), module);          return "error";
 }
return "success";

...

After writting event in Java don't forget to compile it by running "ant" command. At this moment you will need to add build.xml file to your component directory i.e. at hot-deploy/practice/ For the content of build.xml file you can refer "example" component.
Here in build.xml file ensure one thing you are having follwing entry:

Code Block
<target name="classpath">
    <path id="local.class.path">
        <fileset dir="../../framework/base/lib/j2eespecs" includes="*.jar"/>
    </path>
</target>

...

This will needed for the classes like

Code Block
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

...

Step - 2 :  Now you have to create a file by name "secas.xml" in "servicedef" directory. Seca definition will come here. (Take reference from secas.xml of "party" component). This will be

Code Block
<eca service="createPracticePerson" event="commit">
    <condition field-name="partyId" operator="is-not-empty"/>
    <action service="createPartyRoleVisitor" mode="sync"/>
</eca>

...

Step - 2 :  Now you have to create a file by name "eecas.xml" in "entitydef" directory, which will be in your component directory "practice". Eeca definition will come here. (Take reference from eecas.xml of "accounting" component). This will be :

Code Block
<\!-\- To create party role whenever a party is created \-->
<eca entity="Party" operation="create" event="return">
    <condition field-name="partyId" operator="is-not-empty"/>
    <action service="createPartyRoleCustomer" mode="sync"/>
</eca>

...

Step - 3 : Do an entry in ofbiz-component.xml file for this seca definition to to be loaded. It will be :

Code Block
<entity-resource type="eca" reader-name="main" loader="main" location="entitydef/eecas.xml"/>

...

 Create a group service by name "partyGroup" like :

Code Block
<\!-\- Group service \-->
<service name="partyGroup" engine="group" auth="true">
    <description>Creates a party, person and party role Client</description>
    <group>
        <invoke name="createPracticePerson" result-to-context="true"/>
        <invoke name="createPartyRoleClient"/>
    </group>
</service>

...

Step - 2 : Create new screen, form and service for creating a person. Here service will implement the interface. (For creating interface take reference from services_fixedasset.xml of accounting component) it will be like :

Code Block
<!-- Peson Interface -->
<service name="createPersonInterface" engine="interface" location="" invoke="">
    <attribute name="firstName" mode="IN" type="String" optional="false"/>
    <attribute name="middleName" mode="IN" type="String" optional="true"/>
    <attribute name="lastName" mode="IN" type="String" optional="false"/>
    <attribute name="suffix" mode="IN" type="String" optional="true"/>
</service>

<service name="createPracticePersonInterfaceService" engine="simple"
        location="org/hotwax/practice/PracticeServices.xml" invoke="createPracticePersonInterfaceService" auth="false">
    <description>Creates a new Person</description>
    <implements service="createPersonInterface"/>
    <attribute name="partyId" mode="OUT" type="String" optional="false"/>
    <override name="suffix" optional="false"/>
</service>

...

Step - 3 : For loading the defintion you need to do an entry in your ofbiz-component.xml file like:

Code Block
<entity-resource type="model" reader-name="main" loader="main" location="entitydef/entitymodel.xml"/>

...

Step - 1 :  For extending an entity you can do in this manner in the entitydef/entitymodel.xml file of your custom application.

Code Block
<extend-entity entity-name="">
    <field name="" type=""/>
</extend-entity>

...

Step - 2 : Now we are going to create the data for a user for this we have to prepare it in a specific order for a party like :

Code Block
<?xml version="1.0" encoding="UTF-8"?>
<entity-engine-xml>
    <Party partyId="DemoUser" partyTypeId="PERSON"/>
    <Person partyId="DemoUser" firstName="Practice" lastName="Person"/>
    <PartyRole partyId="DemoUser" roleTypeId="VISITOR"/>

    <ContactMech contactMechId="5000" contactMechTypeId="EMAIL_ADDRESS" infoString="practice.person@gmail.com"/>
    <PartyContactMech partyId="DemoUser" contactMechId="5000" fromDate="2001-05-13 00:00:00.000" allowSolicitation="Y"/>
    <PartyContactMechPurpose partyId="DemoUser" contactMechId="5000" contactMechPurposeTypeId="PRIMARY_EMAIL" fromDate="2001-05-13 00:00:00.000"/>
</entity-engine-xml>

...

The purpose is to create a record for a party who is a person with a role of VISITOR and creating an email address which is a primary email address for that party.
Step - 3:  Now we have to an entry in ofbiz-component.xml file :

Code Block
<entity-resource type="data" reader-name="demo" loader="main" location="data/PracticeData.xml"/>

...