You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ofbiz.apache.org by ja...@apache.org on 2007/03/29 21:12:11 UTC

svn commit: r523801 - in /ofbiz/trunk: applications/content/template/email/ applications/content/widget/ framework/service/config/ framework/service/dtd/ framework/service/src/org/ofbiz/service/ framework/service/src/org/ofbiz/service/config/

Author: jaz
Date: Thu Mar 29 12:12:10 2007
New Revision: 523801

URL: http://svn.apache.org/viewvc?view=rev&rev=523801
Log:
implemented internal email notifications for service invocations; configure groups for notifications, setup templates, email addresses and assign services to groups (serviceengine.xml) all services belong to the default group, in case you want to monitor all errors, failures and/or success

Added:
    ofbiz/trunk/applications/content/template/email/
    ofbiz/trunk/applications/content/template/email/servicenotification.ftl   (with props)
    ofbiz/trunk/applications/content/widget/EmailScreens.xml   (with props)
    ofbiz/trunk/framework/service/src/org/ofbiz/service/ModelNotification.java   (with props)
Modified:
    ofbiz/trunk/framework/service/config/serviceengine.xml
    ofbiz/trunk/framework/service/dtd/service-config.xsd
    ofbiz/trunk/framework/service/dtd/services.xsd
    ofbiz/trunk/framework/service/src/org/ofbiz/service/DispatchContext.java
    ofbiz/trunk/framework/service/src/org/ofbiz/service/ModelParam.java
    ofbiz/trunk/framework/service/src/org/ofbiz/service/ModelService.java
    ofbiz/trunk/framework/service/src/org/ofbiz/service/ModelServiceReader.java
    ofbiz/trunk/framework/service/src/org/ofbiz/service/ServiceDispatcher.java
    ofbiz/trunk/framework/service/src/org/ofbiz/service/config/ServiceConfigUtil.java

Added: ofbiz/trunk/applications/content/template/email/servicenotification.ftl
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/content/template/email/servicenotification.ftl?view=auto&rev=523801
==============================================================================
--- ofbiz/trunk/applications/content/template/email/servicenotification.ftl (added)
+++ ofbiz/trunk/applications/content/template/email/servicenotification.ftl Thu Mar 29 12:12:10 2007
@@ -0,0 +1,14 @@
+
+<pre>
+The service : ${service.name}
+
+The Context :
+  <#list serviceContext.keySet() as ckey>
+      ${ckey?if_exists} --> ${(serviceContext.get(ckey))?if_exists}
+  </#list>
+
+The Result :
+  <#list serviceResult.keySet() as rkey>
+      ${rkey?if_exists} --> ${(serviceResult.get(rkey))?if_exists}
+  </#list>
+</pre> 
\ No newline at end of file

Propchange: ofbiz/trunk/applications/content/template/email/servicenotification.ftl
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: ofbiz/trunk/applications/content/template/email/servicenotification.ftl
------------------------------------------------------------------------------
    svn:keywords = "Date Rev Author URL Id"

Propchange: ofbiz/trunk/applications/content/template/email/servicenotification.ftl
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: ofbiz/trunk/applications/content/widget/EmailScreens.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/content/widget/EmailScreens.xml?view=auto&rev=523801
==============================================================================
--- ofbiz/trunk/applications/content/widget/EmailScreens.xml (added)
+++ ofbiz/trunk/applications/content/widget/EmailScreens.xml Thu Mar 29 12:12:10 2007
@@ -0,0 +1,32 @@
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+  -->
+
+<screens xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:noNamespaceSchemaLocation="http://www.ofbiz.org/dtds/widget-screen.xsd">
+    <!-- Simple service notification screen -->
+    <screen name="ServiceNotification">
+        <section>
+            <widgets>
+                <platform-specific>
+                    <html><html-template location="component://content/template/email/servicenotification.ftl"/></html>
+                </platform-specific>
+            </widgets>
+        </section>
+    </screen>
+</screens>
\ No newline at end of file

Propchange: ofbiz/trunk/applications/content/widget/EmailScreens.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: ofbiz/trunk/applications/content/widget/EmailScreens.xml
------------------------------------------------------------------------------
    svn:keywords = "Date Rev Author URL Id"

Propchange: ofbiz/trunk/applications/content/widget/EmailScreens.xml
------------------------------------------------------------------------------
    svn:mime-type = text/xml

Modified: ofbiz/trunk/framework/service/config/serviceengine.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/service/config/serviceengine.xml?view=diff&rev=523801&r1=523800&r2=523801
==============================================================================
--- ofbiz/trunk/framework/service/config/serviceengine.xml (original)
+++ ofbiz/trunk/framework/service/config/serviceengine.xml Thu Mar 29 12:12:10 2007
@@ -20,69 +20,83 @@
 
 <service-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xsi:noNamespaceSchemaLocation="http://www.ofbiz.org/dtds/service-config.xsd">
-    <!-- Name of the service to use for authorization -->
-    <authorization service-name="userLogin"/>
-
-    <!-- Thread pool configuration (max/min threads, uses to live and time to live) -->
-    <thread-pool send-to-pool="pool"
-                 purge-job-days="4"
-                 failed-retry-min="3"
-                 ttl="18000000"
-                 wait-millis="750"
-                 jobs="10"
-                 min-threads="5"
-                 max-threads="15"
-                 poll-enabled="true"
-                 poll-db-millis="20000">
-        <run-from-pool name="pool"/>
-    </thread-pool>
-
-    <!-- Service Engine Configuration -->
-    <engine name="bsh" class="org.ofbiz.service.engine.BeanShellEngine"/>
-    <engine name="group" class="org.ofbiz.service.group.ServiceGroupEngine"/>    
-    <engine name="http" class="org.ofbiz.service.engine.HttpEngine"/>
-    <engine name="interface" class="org.ofbiz.service.engine.InterfaceEngine"/>
-    <engine name="jacl" class="org.ofbiz.service.engine.BSFEngine"/>
-    <engine name="java" class="org.ofbiz.service.engine.StandardJavaEngine"/>
-    <engine name="javascript" class="org.ofbiz.service.engine.BSFEngine"/>
-    <engine name="jms" class="org.ofbiz.service.jms.JmsServiceEngine"/> 
-    <engine name="jpython" class="org.ofbiz.service.engine.BSFEngine"/>
-    <engine name="route" class="org.ofbiz.service.engine.RouteEngine"/>
-    <engine name="rmi" class="org.ofbiz.service.rmi.RmiServiceEngine"/>
-    <engine name="simple" class="org.ofbiz.minilang.SimpleServiceEngine"/>
-    <engine name="soap" class="org.ofbiz.service.engine.SOAPClientEngine"/>
-    <engine name="ofbiz-workflow" class="org.ofbiz.workflow.WorkflowEngine"/>
-    <engine name="workflow" class="org.ofbiz.shark.service.SharkServiceEngine"/>
-
-    <service-location name="main-rmi" location="rmi://localhost:1099/RMIDispatcher"/>
-    <service-location name="main-http" location="http://localhost:8080/webtools/control/httpService"/>
-
-    <service-location name="entity-sync-rmi" location="rmi://localhost:1099/RMIDispatcher"/>
-    <service-location name="entity-sync-http" location="http://localhost:8080/webtools/control/httpService"/>
-
-    <service-location name="rita-rmi" location="rmi://localhost:1099/RMIDispatcher"/>
-    <service-location name="eedcc-test" location="http://localhost:8080/webtools/control/httpService"/>
-
-    <!-- Start-Up Services -->
-    <!--
-       - runtime-data-id refers to the RuntimeData entity for in-parameters
-       - runtime-delay is the milliseconds after startup this service should run
-       - run-in-pool is the name of the pool to run the job in; defaults to the send-to-poll (above)
-
-    <startup-service name="testScv" runtime-data-id="9900" runtime-delay="0" run-in-pool="pool"/>
-    -->   
-
-    <!-- JMS Service Queue/Topic Configuration -->
-    <!--
-    <jms-service name="serviceMessenger" send-mode="all">
-        <server jndi-server-name="default"
-                jndi-name="jms/TopicConnectionFactory"
-                topic-queue="jms/OFBTopic"
-                type="topic"
-                username="admin"
-                password="admin"
-                listen="true"/>
-    </jms-service>
-    -->
 
+    <service-engine name="default">
+        <!-- Name of the service to use for authorization -->
+        <authorization service-name="userLogin"/>
+
+        <!-- Thread pool configuration (max/min threads, uses to live and time to live) -->
+        <thread-pool send-to-pool="pool"
+                     purge-job-days="4"
+                     failed-retry-min="3"
+                     ttl="18000000"
+                     wait-millis="750"
+                     jobs="10"
+                     min-threads="5"
+                     max-threads="15"
+                     poll-enabled="true"
+                     poll-db-millis="20000">
+            <run-from-pool name="pool"/>
+        </thread-pool>
+
+        <!-- Service Engine Configuration -->
+        <engine name="bsh" class="org.ofbiz.service.engine.BeanShellEngine"/>
+        <engine name="group" class="org.ofbiz.service.group.ServiceGroupEngine"/>
+        <engine name="http" class="org.ofbiz.service.engine.HttpEngine"/>
+        <engine name="interface" class="org.ofbiz.service.engine.InterfaceEngine"/>
+        <engine name="jacl" class="org.ofbiz.service.engine.BSFEngine"/>
+        <engine name="java" class="org.ofbiz.service.engine.StandardJavaEngine"/>
+        <engine name="javascript" class="org.ofbiz.service.engine.BSFEngine"/>
+        <engine name="jms" class="org.ofbiz.service.jms.JmsServiceEngine"/>
+        <engine name="jpython" class="org.ofbiz.service.engine.BSFEngine"/>
+        <engine name="route" class="org.ofbiz.service.engine.RouteEngine"/>
+        <engine name="rmi" class="org.ofbiz.service.rmi.RmiServiceEngine"/>
+        <engine name="simple" class="org.ofbiz.minilang.SimpleServiceEngine"/>
+        <engine name="soap" class="org.ofbiz.service.engine.SOAPClientEngine"/>
+        <engine name="ofbiz-workflow" class="org.ofbiz.workflow.WorkflowEngine"/>
+        <engine name="workflow" class="org.ofbiz.shark.service.SharkServiceEngine"/>
+
+        <service-location name="main-rmi" location="rmi://localhost:1099/RMIDispatcher"/>
+        <service-location name="main-http" location="http://localhost:8080/webtools/control/httpService"/>
+
+        <service-location name="entity-sync-rmi" location="rmi://localhost:1099/RMIDispatcher"/>
+        <service-location name="entity-sync-http" location="http://localhost:8080/webtools/control/httpService"/>
+
+        <service-location name="rita-rmi" location="rmi://localhost:1099/RMIDispatcher"/>
+        <service-location name="eedcc-test" location="http://localhost:8080/webtools/control/httpService"/>
+
+        <!-- default notification group for all services loaded with 'main' loader
+             - uncomment this to enable error notification for all services
+             - (default.fail.main, default.success.main can also be defined
+                     
+        <notification-group name="default.error.main">
+            <notification subject="Service Error ${model.serviceName}"
+                          screen="component://content/widget/EmailScreens.xml#ServiceNotification"/>
+            <notify type="from">ofbiz@test.com</notify>
+            <notify type="to">error@test.com</notify>
+        </notification-group>
+        -->
+        
+        <!-- Start-Up Services -->
+        <!--
+           - runtime-data-id refers to the RuntimeData entity for in-parameters
+           - runtime-delay is the milliseconds after startup this service should run
+           - run-in-pool is the name of the pool to run the job in; defaults to the send-to-poll (above)
+
+        <startup-service name="testScv" runtime-data-id="9900" runtime-delay="0" run-in-pool="pool"/>
+        -->
+
+        <!-- JMS Service Queue/Topic Configuration -->
+        <!--
+        <jms-service name="serviceMessenger" send-mode="all">
+            <server jndi-server-name="default"
+                    jndi-name="jms/TopicConnectionFactory"
+                    topic-queue="jms/OFBTopic"
+                    type="topic"
+                    username="admin"
+                    password="admin"
+                    listen="true"/>
+        </jms-service>
+        -->
+    </service-engine>
 </service-config>

Modified: ofbiz/trunk/framework/service/dtd/service-config.xsd
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/service/dtd/service-config.xsd?view=diff&rev=523801&r1=523800&r2=523801
==============================================================================
--- ofbiz/trunk/framework/service/dtd/service-config.xsd (original)
+++ ofbiz/trunk/framework/service/dtd/service-config.xsd Thu Mar 29 12:12:10 2007
@@ -22,10 +22,18 @@
     <xs:element name="service-config">
         <xs:complexType>
             <xs:sequence>
+                <xs:element minOccurs="1" maxOccurs="unbounded" ref="service-engine"/>
+            </xs:sequence>
+        </xs:complexType>
+    </xs:element>    
+    <xs:element name="service-engine">
+        <xs:complexType>
+            <xs:sequence>
                 <xs:element ref="authorization"/>
                 <xs:element ref="thread-pool"/>
                 <xs:element minOccurs="0" maxOccurs="unbounded" ref="engine"/>
                 <xs:element minOccurs="0" maxOccurs="unbounded" ref="service-location"/>
+                <xs:element minOccurs="0" maxOccurs="unbounded" ref="notification-group"/>
                 <xs:element minOccurs="0" maxOccurs="unbounded" ref="startup-service"/>
                 <xs:element minOccurs="0" maxOccurs="unbounded" ref="resource-loader"/>
                 <xs:element minOccurs="0" maxOccurs="unbounded" ref="global-services"/>
@@ -33,8 +41,12 @@
                 <xs:element minOccurs="0" maxOccurs="unbounded" ref="service-ecas"/>
                 <xs:element minOccurs="0" maxOccurs="unbounded" ref="jms-service"/>
             </xs:sequence>
+            <xs:attributeGroup ref="attlist.service-engine"/>
         </xs:complexType>
     </xs:element>
+    <xs:attributeGroup name="attlist.service-engine">
+        <xs:attribute type="xs:string" name="name" use="required"/>
+    </xs:attributeGroup>
     <xs:element name="authorization">
         <xs:complexType>
             <xs:attributeGroup ref="attlist.authorization"/>
@@ -197,5 +209,45 @@
             </xs:simpleType>
         </xs:attribute>
         <xs:attribute type="xs:string" name="listener-class"/>
+    </xs:attributeGroup>
+
+    <xs:element name="notification-group">
+        <xs:complexType>
+            <xs:sequence>
+                <xs:element minOccurs="1" maxOccurs="1" ref="notification"/>
+                <xs:element minOccurs="2" maxOccurs="unbounded" ref="notify"/>
+            </xs:sequence>
+            <xs:attributeGroup ref="attlist.notification-group"/>
+        </xs:complexType>
+    </xs:element>
+    <xs:attributeGroup name="attlist.notification-group">
+        <xs:attribute type="xs:string" name="name"/>
+    </xs:attributeGroup>
+    <xs:element name="notification">
+        <xs:complexType>            
+            <xs:attributeGroup ref="attlist.notification"/>
+        </xs:complexType>
+    </xs:element>
+    <xs:attributeGroup name="attlist.notification">
+        <xs:attribute type="xs:string" name="subject" use="required"/>
+        <xs:attribute type="xs:string" name="screen" use="required"/>
+        <xs:attribute type="xs:string" name="service" default="sendMailFromScreen"/>
+    </xs:attributeGroup>
+    <xs:element name="notify">
+        <xs:complexType mixed="true">
+            <xs:attributeGroup ref="attlist.notify"/>
+        </xs:complexType>
+    </xs:element>
+    <xs:attributeGroup name="attlist.notify">
+        <xs:attribute name="type" use="required">
+            <xs:simpleType>
+                <xs:restriction base="xs:token">
+                    <xs:enumeration value="to"/>
+                    <xs:enumeration value="cc"/>
+                    <xs:enumeration value="bcc"/>
+                    <xs:enumeration value="from"/>
+                </xs:restriction>
+            </xs:simpleType>
+        </xs:attribute>
     </xs:attributeGroup>
 </xs:schema>

Modified: ofbiz/trunk/framework/service/dtd/services.xsd
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/service/dtd/services.xsd?view=diff&rev=523801&r1=523800&r2=523801
==============================================================================
--- ofbiz/trunk/framework/service/dtd/services.xsd (original)
+++ ofbiz/trunk/framework/service/dtd/services.xsd Thu Mar 29 12:12:10 2007
@@ -112,6 +112,23 @@
             </xs:simpleType>
         </xs:attribute>
     </xs:attributeGroup>
+    <xs:element name="notification">
+        <xs:complexType>
+            <xs:attributeGroup ref="attlist.notification"/>
+        </xs:complexType>
+    </xs:element>
+    <xs:attributeGroup name="attlist.notification">
+        <xs:attribute name="event" use="required">
+            <xs:simpleType>
+                <xs:restriction base="xs:token">
+                    <xs:enumeration value="success"/>
+                    <xs:enumeration value="error"/>
+                    <xs:enumeration value="fail"/>                    
+                </xs:restriction>
+            </xs:simpleType>
+        </xs:attribute>
+        <xs:attribute type="xs:string" name="group" use="required"/>        
+    </xs:attributeGroup>
     <xs:element name="permission-service">
         <xs:complexType>
             <xs:attributeGroup ref="attlist.permission-service"/>

Modified: ofbiz/trunk/framework/service/src/org/ofbiz/service/DispatchContext.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/service/src/org/ofbiz/service/DispatchContext.java?view=diff&rev=523801&r1=523800&r2=523801
==============================================================================
--- ofbiz/trunk/framework/service/src/org/ofbiz/service/DispatchContext.java (original)
+++ ofbiz/trunk/framework/service/src/org/ofbiz/service/DispatchContext.java Thu Mar 29 12:12:10 2007
@@ -63,7 +63,7 @@
 
     /** 
      * Creates new DispatchContext
-     * @param readers a collection of reader URLs
+     * @param localReaders a collection of reader URLs
      * @param loader the classloader to use for dispatched services
      */
     public DispatchContext(String name, Collection localReaders, ClassLoader loader, LocalDispatcher dispatcher) {
@@ -148,7 +148,7 @@
      * @throws GenericServiceException
      */
     public Map makeValidContext(ModelService model, String mode, Map context) throws GenericServiceException {
-        Map newContext = null;
+        Map newContext;
         
         int modeInt = 0;
         if (mode.equalsIgnoreCase("in")) {
@@ -290,7 +290,7 @@
                 if (serviceMap == null) {
                     serviceMap = FastMap.newInstance();
 
-                    Element rootElement = null;
+                    Element rootElement;
 
                     try {
                         rootElement = ServiceConfigUtil.getXmlRootElement();

Added: ofbiz/trunk/framework/service/src/org/ofbiz/service/ModelNotification.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/service/src/org/ofbiz/service/ModelNotification.java?view=auto&rev=523801
==============================================================================
--- ofbiz/trunk/framework/service/src/org/ofbiz/service/ModelNotification.java (added)
+++ ofbiz/trunk/framework/service/src/org/ofbiz/service/ModelNotification.java Thu Mar 29 12:12:10 2007
@@ -0,0 +1,168 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+package org.ofbiz.service;
+
+import org.ofbiz.service.config.ServiceConfigUtil;
+import org.ofbiz.base.util.StringUtil;
+import org.ofbiz.base.util.Debug;
+
+import java.util.List;
+import java.util.Map;
+
+import javolution.util.FastMap;
+
+/**
+ * ModelNotification
+ */
+public class ModelNotification {
+
+    public static final String module = ModelNotification.class.getName();
+
+    public String notificationGroupName;
+    public String notificationEvent;
+    public String notificationMode;
+
+    public void callNotify(DispatchContext dctx, ModelService model, Map context, Map result) {
+        String thisEvent = (String) result.get(ModelService.RESPONSE_MESSAGE);
+        if (notificationEvent.equals(thisEvent)) {
+            String notificationService = this.getService();
+            if (notificationService != null) {
+                try {
+                    Map notifyContext = this.buildContext(context, result, model);
+                    dctx.getDispatcher().runSync(getService(), notifyContext, 90, true);
+                } catch (GenericServiceException e) {
+                    Debug.logError(e, module);
+                }
+            }
+        }
+    }
+
+    public Map buildContext(Map context, Map result, ModelService model) throws GenericServiceException {
+        Map userLogin = (Map) context.get("userLogin");
+        String partyId = null;
+        if (userLogin != null) {
+            partyId = (String) userLogin.get("partyId");
+        }
+
+        String screen = getScreen();
+        if (screen == null) {
+            throw new GenericServiceException("SCREEN is a required attribute; check serviceengine.xml group definition; cannot generate notification");
+        }
+
+        String subject = getSubject();
+        String from = buildFrom();
+        String bcc = buildBcc();
+        String cc = buildCc();
+        String to = buildTo();
+        if (subject == null || from == null || to == null) {
+            throw new GenericServiceException("TO, FROM and SUBJECT are required for notifications; check serviceengine.xml group definition");
+        }
+
+        // template context
+        Map notifyContext = FastMap.newInstance();
+        Map bodyParams = FastMap.newInstance();
+        bodyParams.put("serviceContext", context);
+        bodyParams.put("serviceResult", result);
+        bodyParams.put("service", model);
+
+        // notification context
+        notifyContext.put("bodyParameters", bodyParams);
+
+        notifyContext.put("sendFrom", from);
+        notifyContext.put("sendBcc", bcc);
+        notifyContext.put("sendCc", cc);
+        notifyContext.put("sendTo", to);
+        notifyContext.put("subject", subject);
+        notifyContext.put("partyId", partyId);
+
+        notifyContext.put("bodyScreenUri", screen);
+        
+        return notifyContext;
+    }
+
+    public String buildTo() {
+        ServiceConfigUtil.NotificationGroup group = ServiceConfigUtil.getNotificationGroup(notificationGroupName);
+        if (group != null) {
+            List addr = group.getAddress("to");
+            if (addr != null && addr.size() > 0) {
+                return StringUtil.join(addr, ",");
+            }
+        }
+        return null;
+    }
+
+    public String buildCc() {
+        ServiceConfigUtil.NotificationGroup group = ServiceConfigUtil.getNotificationGroup(notificationGroupName);
+        if (group != null) {
+            List addr = group.getAddress("cc");
+            if (addr != null) {
+                return StringUtil.join(addr, ",");
+            }
+        }
+        return null;
+    }
+
+    public String buildBcc() {
+        ServiceConfigUtil.NotificationGroup group = ServiceConfigUtil.getNotificationGroup(notificationGroupName);
+        if (group != null) {
+            List addr = group.getAddress("bcc");
+            if (addr != null && addr.size() > 0) {
+                return StringUtil.join(addr, ",");
+            }
+        }
+        return null;
+    }
+
+    public String buildFrom() {
+        ServiceConfigUtil.NotificationGroup group = ServiceConfigUtil.getNotificationGroup(notificationGroupName);
+        if (group != null) {
+            List addr = group.getAddress("from");
+            if (addr != null && addr.size() > 0) {
+                return (String) addr.get(0);
+            }
+        }
+        return null;
+    }
+
+    public String getSubject() {
+        ServiceConfigUtil.NotificationGroup group = ServiceConfigUtil.getNotificationGroup(notificationGroupName);
+        if (group != null) {
+            return group.getSubject();
+        }
+        return null;
+    }
+
+    public String getScreen() {
+        ServiceConfigUtil.NotificationGroup group = ServiceConfigUtil.getNotificationGroup(notificationGroupName);
+        if (group != null) {
+            return group.getScreen();
+        }
+        return null;
+    }
+
+    public String getService() {
+        ServiceConfigUtil.NotificationGroup group = ServiceConfigUtil.getNotificationGroup(notificationGroupName);
+        if (group != null) {
+            // only service supported at this time
+            return "sendMailFromScreen";
+        }
+        return null;
+    }
+}

Propchange: ofbiz/trunk/framework/service/src/org/ofbiz/service/ModelNotification.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: ofbiz/trunk/framework/service/src/org/ofbiz/service/ModelNotification.java
------------------------------------------------------------------------------
    svn:keywords = "Date Rev Author URL Id"

Propchange: ofbiz/trunk/framework/service/src/org/ofbiz/service/ModelNotification.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: ofbiz/trunk/framework/service/src/org/ofbiz/service/ModelParam.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/service/src/org/ofbiz/service/ModelParam.java?view=diff&rev=523801&r1=523800&r2=523801
==============================================================================
--- ofbiz/trunk/framework/service/src/org/ofbiz/service/ModelParam.java (original)
+++ ofbiz/trunk/framework/service/src/org/ofbiz/service/ModelParam.java Thu Mar 29 12:12:10 2007
@@ -127,13 +127,14 @@
         buf.append(fieldName).append("::");
         buf.append(stringMapPrefix).append("::");
         buf.append(stringListSuffix).append("::");
-        buf.append(validators.toString()).append("::");
         buf.append(optional).append("::");
         buf.append(overrideOptional).append("::");
         buf.append(formDisplay).append("::");
         buf.append(overrideFormDisplay).append("::");
         buf.append(defaultValue).append("::");
         buf.append(internal);
+        if (validators != null)
+            buf.append(validators.toString()).append("::");
         return buf.toString();
     }
 

Modified: ofbiz/trunk/framework/service/src/org/ofbiz/service/ModelService.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/service/src/org/ofbiz/service/ModelService.java?view=diff&rev=523801&r1=523800&r2=523801
==============================================================================
--- ofbiz/trunk/framework/service/src/org/ofbiz/service/ModelService.java (original)
+++ ofbiz/trunk/framework/service/src/org/ofbiz/service/ModelService.java Thu Mar 29 12:12:10 2007
@@ -20,6 +20,7 @@
 
 import java.util.*;
 import java.lang.reflect.Method;
+import java.lang.reflect.Field;
 import java.io.Serializable;
 
 import javax.wsdl.*;
@@ -55,7 +56,7 @@
 /**
  * Generic Service Model Class
  */
-public class ModelService implements Serializable {
+public class ModelService extends AbstractMap implements Serializable {
 
     public static final String module = ModelService.class.getName();
 
@@ -97,6 +98,9 @@
     /** The default Entity to use for auto-attributes */
     public String defaultEntityName;
 
+    /** The loader which loaded this definition */
+    public String fromLoader;
+    
     /** Does this service require authorization */
     public boolean auth;
 
@@ -139,6 +143,9 @@
     /** List of permission groups for service invocation */
     public List permissionGroups = FastList.newInstance();
 
+    /** List of email-notifications for this service */
+    public List notifications = FastList.newInstance();
+
     /** Internal Service Group */
     public GroupModel internalGroup = null;
     
@@ -183,6 +190,31 @@
         }
     }
 
+    public Object get(Object name) {
+        Field field;
+        try {
+            field = this.getClass().getField(name.toString());
+        } catch (NoSuchFieldException e) {
+            return null;
+        }
+        if (field != null) {
+            try {
+                return field.get(this);
+            } catch (IllegalAccessException e) {
+                return null;
+            }
+        }
+        return null;
+    }
+
+    public Set entrySet() {
+        return null;
+    }
+
+    public Object put(Object o1, Object o2) {
+        return null;
+    }
+
     public String toString() {
         StringBuffer buf = new StringBuffer();
         buf.append(name).append("::");
@@ -845,6 +877,17 @@
             result.put("hasPermission", Boolean.FALSE);
             result.put("failMessage", "No ModelService found; no service name specified!");
             return result;
+        }
+    }
+
+    /**
+     * Evaluates notifications
+     */
+    public void evalNotifications(DispatchContext dctx, Map context, Map result) {
+        Iterator i = this.notifications.iterator();
+        while (i.hasNext()) {
+            ModelNotification notify = (ModelNotification) i.next();
+            notify.callNotify(dctx, this, context, result);
         }
     }
 

Modified: ofbiz/trunk/framework/service/src/org/ofbiz/service/ModelServiceReader.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/service/src/org/ofbiz/service/ModelServiceReader.java?view=diff&rev=523801&r1=523800&r2=523801
==============================================================================
--- ofbiz/trunk/framework/service/src/org/ofbiz/service/ModelServiceReader.java (original)
+++ ofbiz/trunk/framework/service/src/org/ofbiz/service/ModelServiceReader.java Thu Mar 29 12:12:10 2007
@@ -74,25 +74,12 @@
         }
 
         ModelServiceReader reader = new ModelServiceReader(readerURL, dctx);
-        if (reader == null) {
-            Debug.logError("Could not load the reader for the reader URL " + readerURL, module);
-            return null;
-        }
-
-        Map serviceMap = reader.getModelServices();
-        return serviceMap;
+        return reader.getModelServices();
     }
 
     public static Map getModelServiceMap(ResourceHandler handler, DispatchContext dctx) {
-        ModelServiceReader reader;
-        reader = new ModelServiceReader(handler, dctx);
-        if (reader == null) {
-            Debug.logError("Could not load the reader for " + handler, module);
-            return null;
-        }
-
-        Map serviceMap = reader.getModelServices();
-        return serviceMap;
+        ModelServiceReader reader = new ModelServiceReader(handler, dctx);
+        return reader.getModelServices();
     }
 
     protected ModelServiceReader(URL readerURL, DispatchContext dctx) {
@@ -273,8 +260,9 @@
         service.location = UtilXml.checkEmpty(serviceElement.getAttribute("location"));
         service.invoke = UtilXml.checkEmpty(serviceElement.getAttribute("invoke"));  
         service.defaultEntityName = UtilXml.checkEmpty(serviceElement.getAttribute("default-entity-name"));
-        
-        // these default to true; if anything but true, make false    
+        service.fromLoader = isFromURL ? readerURL.toExternalForm() : handler.getLoaderName();        
+
+        // these default to true; if anything but true, make false
         service.auth = "true".equalsIgnoreCase(serviceElement.getAttribute("auth"));
         service.export = "true".equalsIgnoreCase(serviceElement.getAttribute("export"));
         service.debug = "true".equalsIgnoreCase(serviceElement.getAttribute("debug"));
@@ -315,6 +303,7 @@
         
         // contruct the context
         service.contextInfo = FastMap.newInstance();
+        this.createNotification(serviceElement, service);
         this.createPermission(serviceElement, service);
         this.createPermGroups(serviceElement, service);
         this.createGroupDefs(serviceElement, service);
@@ -342,6 +331,36 @@
             }
         }
         return value;
+    }
+
+    protected void createNotification(Element baseElement, ModelService model) {
+        List n = UtilXml.childElementList(baseElement, "notification");
+        // default notification groups
+        ModelNotification nSuccess = new ModelNotification();
+        nSuccess.notificationEvent = "success";
+        nSuccess.notificationGroupName = "default.success." + model.fromLoader;
+        model.notifications.add(nSuccess);
+
+        ModelNotification nFail = new ModelNotification();
+        nFail.notificationEvent = "fail";
+        nFail.notificationGroupName = "default.fail." + model.fromLoader;
+        model.notifications.add(nFail);
+
+        ModelNotification nError = new ModelNotification();
+        nError.notificationEvent = "error";
+        nError.notificationGroupName = "default.error." + model.fromLoader;
+        model.notifications.add(nError);
+
+        if (n != null) {
+            Iterator i = n.iterator();
+            while (i.hasNext()) {
+                Element e = (Element) i.next();
+                ModelNotification notify = new ModelNotification();
+                notify.notificationEvent = e.getAttribute("event");
+                notify.notificationGroupName = e.getAttribute("group");
+                model.notifications.add(notify);                
+            }
+        }
     }
 
     protected void createPermission(Element baseElement, ModelService model) {

Modified: ofbiz/trunk/framework/service/src/org/ofbiz/service/ServiceDispatcher.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/service/src/org/ofbiz/service/ServiceDispatcher.java?view=diff&rev=523801&r1=523800&r2=523801
==============================================================================
--- ofbiz/trunk/framework/service/src/org/ofbiz/service/ServiceDispatcher.java (original)
+++ ofbiz/trunk/framework/service/src/org/ofbiz/service/ServiceDispatcher.java Thu Mar 29 12:12:10 2007
@@ -429,6 +429,9 @@
                         throw new GenericServiceException(errMsg);
                     }
                 }
+
+                // call notifications -- event is determined from the result (success, error, fail)
+                modelService.evalNotifications(this.getLocalContext(localName), context, result);
             }
         } catch (GenericTransactionException te) {
             Debug.logError(te, "Problems with the transaction", module);

Modified: ofbiz/trunk/framework/service/src/org/ofbiz/service/config/ServiceConfigUtil.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/service/src/org/ofbiz/service/config/ServiceConfigUtil.java?view=diff&rev=523801&r1=523800&r2=523801
==============================================================================
--- ofbiz/trunk/framework/service/src/org/ofbiz/service/config/ServiceConfigUtil.java (original)
+++ ofbiz/trunk/framework/service/src/org/ofbiz/service/config/ServiceConfigUtil.java Thu Mar 29 12:12:10 2007
@@ -20,30 +20,32 @@
 
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
+import java.io.Serializable;
 
 import javolution.util.FastList;
+import javolution.util.FastMap;
 
 import org.ofbiz.base.config.GenericConfigException;
 import org.ofbiz.base.config.ResourceLoader;
 import org.ofbiz.base.util.Debug;
 import org.ofbiz.base.util.UtilXml;
-import org.w3c.dom.Document;
+import org.ofbiz.base.util.cache.UtilCache;
 import org.w3c.dom.Element;
 
 /**
  * Misc. utility method for dealing with the serviceengine.xml file
  */
-public class ServiceConfigUtil {
+public class ServiceConfigUtil implements Serializable {
     
-    public static final String module = ServiceConfigUtil.class.getName();    
+    public static final String module = ServiceConfigUtil.class.getName();
+    public static final String engine = "default";
     public static final String SERVICE_ENGINE_XML_FILENAME = "serviceengine.xml";
+    protected static UtilCache notificationGroupCache = new UtilCache("service.NotificationGroups", 0, 0, false);
 
     public static Element getXmlRootElement() throws GenericConfigException {
-        return ResourceLoader.getXmlRootElement(ServiceConfigUtil.SERVICE_ENGINE_XML_FILENAME);
-    }
-
-    public static Document getXmlDocument() throws GenericConfigException {
-        return ResourceLoader.getXmlDocument(ServiceConfigUtil.SERVICE_ENGINE_XML_FILENAME);
+        Element root = ResourceLoader.getXmlRootElement(ServiceConfigUtil.SERVICE_ENGINE_XML_FILENAME);
+        return UtilXml.firstChildElement(root, "service-engine"); // only look at the first one for now
     }
 
     public static Element getElement(String elementName) {
@@ -87,7 +89,7 @@
     
     public static int getPurgeJobDays() {
         String days = getElementAttr("thread-pool", "purge-job-days");
-        int purgeDays = 0;
+        int purgeDays;
         try {
             purgeDays = Integer.parseInt(days);
         } catch (NumberFormatException e) {
@@ -99,7 +101,7 @@
 
     public static int getFailedRetryMin() {
         String minString = getElementAttr("thread-pool", "failed-retry-min");
-        int retryMin = 30;
+        int retryMin;
         try {
             retryMin = Integer.parseInt(minString);
         } catch (NumberFormatException e) {
@@ -107,5 +109,142 @@
             retryMin = 30;
         }
         return retryMin;
-    }    
+    }
+
+    public static void readNotificationGroups() {
+        Element rootElement = null;
+
+        try {
+            rootElement = ServiceConfigUtil.getXmlRootElement();
+        } catch (GenericConfigException e) {
+            Debug.logError(e, "Error getting Service Engine XML root element", module);
+        }
+
+        FastMap engineNotifyMap = FastMap.newInstance();
+
+        List nGroups = UtilXml.childElementList(rootElement, "notification-group");
+        Iterator i = nGroups.iterator();
+        while (i.hasNext()) {
+            Element e = (Element) i.next();
+            NotificationGroup ng = new NotificationGroup(e);
+            engineNotifyMap.put(ng.getName(), ng);
+        }
+
+        notificationGroupCache.put(engine, engineNotifyMap);
+    }
+
+    public static NotificationGroup getNotificationGroup(String group) {
+        Map engineNotifyMap = (Map) notificationGroupCache.get(engine);
+        if (engineNotifyMap == null) {
+            synchronized(ServiceConfigUtil.class) {
+                engineNotifyMap = (Map) notificationGroupCache.get(engine);
+                if (engineNotifyMap == null) {
+                    readNotificationGroups();
+                }
+            }
+            engineNotifyMap = (Map) notificationGroupCache.get(engine);
+        }
+        if (engineNotifyMap != null) {
+           return (NotificationGroup) engineNotifyMap.get(group);
+        }
+
+        return null;
+    }
+        
+    public static class NotificationGroup implements Serializable {
+        protected Notification notification;
+        protected List notify;
+        protected String name;
+
+        protected NotificationGroup(Element e) {
+            name = e.getAttribute("name");
+            notify = FastList.newInstance();
+            notification = new Notification(UtilXml.firstChildElement(e, "notification"));
+
+            List n = UtilXml.childElementList(e, "notify");
+            Iterator i = n.iterator();
+            while (i.hasNext()) {
+                Element e2 = (Element) i.next();
+                notify.add(new Notify(e2));
+            }
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public Notification getNotification() {
+            return notification;
+        }
+
+        public List getNotify() {
+            return notify;
+        }
+
+        public String getService() {
+            return notification.getService();
+        }
+
+        public String getSubject() {
+            return notification.getSubject();
+        }
+
+        public String getScreen() {
+            return notification.getScreen();
+        }
+
+        public List getAddress(String type) {
+            List l = FastList.newInstance();
+            Iterator i = notify.iterator();
+            while (i.hasNext()) {
+                Notify n = (Notify) i.next();
+                if (n.getType().equals(type)) {
+                    l.add(n.getValue());
+                }
+            }
+
+            return l;
+        }
+
+        class Notification implements Serializable {
+            protected String subject = null;
+            protected String screen = null;
+            protected String service = null;
+
+            public Notification(Element e) {
+                service = e.getAttribute("service");
+                subject = e.getAttribute("subject");
+                screen = e.getAttribute("screen");
+            }
+
+            public String getScreen() {
+                return screen;
+            }
+
+            public String getSubject() {
+                return subject;
+            }
+
+            public String getService() {
+                return service;
+            }
+        }
+
+        class Notify implements Serializable {
+            protected String type;
+            protected String value;
+
+            public Notify(Element e) {
+                type = e.getAttribute("type");
+                value = UtilXml.elementValue(e);
+            }
+
+            public String getType() {
+                return type;
+            }
+            public String getValue() {
+                return value;
+            }
+        }
+    }
 }