View Javadoc

1   /**
2    * Copyright 2005-2006 the original author or authors.
3    *
4    * Licensed under the Gnu General Pubic License, Version 2.0 (the
5    * "License"); you may not use this file except in compliance with
6    * the License. You may obtain a copy of the License at
7    *
8    *      http://www.opensource.org/licenses/gpl-license.php
9    *
10   * This program is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13   * See the Gnu General Public License for more details.
14   */
15  package org.figure8.join.services.notification;
16  
17  import org.figure8.join.core.Configurable;
18  import org.figure8.join.core.ParameterDefinition;
19  import org.figure8.join.core.ContainerContextHandler;
20  import org.figure8.join.core.InfrastructureException;
21  import org.figure8.join.core.InvalidParameterException;
22  import org.figure8.join.core.setup.BootstrapManager;
23  import org.figure8.join.services.remoting.ReportingService;
24  import org.figure8.join.services.remoting.beans.RemoteSubscriber;
25  import org.figure8.join.services.remoting.beans.RemoteMailingList;
26  import org.figure8.join.util.LogUtil;
27  
28  import com.caucho.hessian.client.HessianProxyFactory;
29  
30  import org.apache.commons.logging.Log;
31  
32  import java.util.List;
33  import java.util.Iterator;
34  import java.util.ArrayList;
35  import java.util.Properties;
36  import java.rmi.RemoteException;
37  /**
38   * This is a support class to extend for classes wanting to use {@link SubscribersNotifier}.
39   * @author <a href="mailto:laurent.broudoux@free.fr">Laurent Broudoux</a>
40   * @version $Revision: 1.1 $
41   */
42  public abstract class SubscribersNotifierAdapterSupport implements Configurable{
43  
44     // Static -------------------------------------------------------------------
45  
46     /** Get a commons logger. */
47     private static final Log log = LogUtil.getLog(SubscribersNotifierAdapterSupport.class);
48  
49     /** Name of configurable parameter denoting the key of event to notity. */
50     public static final String EVENT_PARAM = "eventKey";
51     /** Name of configuratble parameter denoting the key of resource to notifiy event for. */
52     public static final String RESOURCE_PARAM = "resourceKey";
53  
54     /** List of {@link ParameterDefinition}s supported by this adapter */
55     protected static List parameters = new ArrayList();
56  
57     /** ParameterDefinition representation of parameter denoting the key of event to notify. */
58     protected static final ParameterDefinition eventParam = new ParameterDefinition(EVENT_PARAM,
59             "The key of event to notify using this notifier", "delivery", true);
60     /** ParameterDefinition representation of parameter denoting the key of resource to notify event for. */
61     protected static final ParameterDefinition resourceParam = new ParameterDefinition(RESOURCE_PARAM,
62             "The key of resource to notify event for", "mydeliverablekey", false);
63  
64  
65     // Attributes ---------------------------------------------------------------
66  
67     /** The name identifying this notifier adapter. */
68     protected String name;
69     /** The key of event to notify to subscribers */
70     private String eventKey;
71     /** The key of resource to notify event for */
72     private String resourceKey;
73  
74  
75     // Constructors -------------------------------------------------------------
76  
77     /** Creates a new instance of SubscribersNotifierAdapterSupport. */
78     protected SubscribersNotifierAdapterSupport(){
79     }
80  
81  
82     // Public -------------------------------------------------------------------
83  
84     /**
85      * Retrieve the name of this adapter.
86      * @return The name identifying this adapter
87      */
88     public String getName(){
89        return name;
90     }
91     /**
92      * Set the name identifying this adapter.
93      * @param name The name of this adapter
94      */
95     public void setName(String name){
96        this.name = name;
97     }
98     /** @return The key of event to notify to subscribers */
99     public String getEventKey(){
100       return eventKey;
101    }
102    /** @param eventKey The key of event to notify to subscribers */
103    public void setEventKey(String eventKey){
104       this.eventKey = eventKey;
105    }
106    /** @return The key of resource to notify event for */
107    public String getResourceKey(){
108       return resourceKey;
109    }
110    /** @param resourceKey The key of resource to notify event for */
111    public void setResourceKey(String resourceKey){
112       this.resourceKey = resourceKey;
113    }
114 
115    /**
116     * Subclasses must implement this method in order to specify the
117     * Notifier implementation to use (and thus the publication media).
118     * @return The notifier implementation
119     */
120    public abstract SubscribersNotifier getSubscribersNotifier();
121 
122 
123    // Implementation of Configurable -------------------------------------------
124 
125    /**
126     * Get this object parameters definitions as a list
127     * @return A list of {@code ParameterDefinition} objects
128     */
129    public List getParameterDefinitionsAsList(){
130       // Use notifier parameters as base.
131       if (parameters.isEmpty()){
132          parameters.addAll(getSubscribersNotifier().getParameterDefinitionsAsList());
133          parameters.add(eventParam);
134          parameters.add(resourceParam);
135       }
136       return parameters;
137    }
138 
139    /**
140     * Get this object parameters definitions as an array
141     * @return An array of {@code ParameterDefinition} objects
142     */
143    public ParameterDefinition[] getParameterDefinitions(){
144       List result = getParameterDefinitionsAsList();
145       return (ParameterDefinition[])result.toArray(new ParameterDefinition[result.size()]);
146    }
147 
148    /**
149     * Set the value of a parameter using its nama
150     * @param parameterName The name of parameter so set value for
151     * @param parameterValue The value of the paramater
152     * @throws InvalidParameterException if this parameter is not supported by this object
153     */
154    public void setParameter(String parameterName, String parameterValue) throws InvalidParameterException{
155       try{
156          // Delegate to notifier implementation class.
157          getSubscribersNotifier().setParameter(parameterName, parameterValue);
158       }
159       catch (InvalidParameterException ipe){
160          // Then test the managed parameters.
161          if (EVENT_PARAM.equals(parameterName))
162             setEventKey(parameterValue);
163          else if (RESOURCE_PARAM.equals(parameterName))
164             setResourceKey(parameterValue);
165          else{
166             log.warn("The parameter '" + parameterName + "' is not supported by SubscribersNotifierAdapterSupport");
167             throw new InvalidParameterException("The parameter '" + parameterName + "' is not supported by SubscribersNotifierAdapterSupport");
168          }
169       }
170    }
171 
172    /**
173     * Set the value of a parameter using its definitions
174     * @param parameter The definitino of the paramater to set
175     * @param parameterValue The value of the parameter
176     * @throws InvalidParameterException if this parameter is not supported by this object
177     */
178    public void setParameter(ParameterDefinition parameter, String parameterValue) throws InvalidParameterException{
179       setParameter(parameter.getName(), parameterValue);
180    }
181 
182    /**
183     * Convenient methods for setting all attributes values using a single method.
184     * @param parameters Properties where keys are parameter names
185     * @throws InvalidParameterException if one of these parameters is not supported by this object
186     */
187    public void setParameters(Properties parameters) throws InvalidParameterException{
188       Iterator keys = parameters.keySet().iterator();
189       while (keys != null && keys.hasNext()){
190          String parameterName = (String)keys.next();
191          String parameterValue = parameters.getProperty(parameterName);
192          setParameter(parameterName, parameterValue);
193       }
194    }
195 
196 
197    // Protected ----------------------------------------------------------------
198 
199    /**
200     * Connect to remote reporting service and retrieve mailing list
201     * @param eventKey The key of event to retrieve mailing list for
202     * @param resourceId The id of resource to retrieve mailing list for (may be null if no resource specified)
203     * @return The corresponding mailing list
204     */
205    protected RemoteMailingList retrieveMailingList(String eventKey, String resourceId) throws Exception{
206       // Just retrieve service and the mailing list.
207       ReportingService service = retrieveReportingService();
208       if (resourceId != null)
209          return service.getMailingList(eventKey, resourceId);
210       // It may have many lists, warn and take the first.
211       RemoteMailingList[] lists = service.getMailingLists(eventKey);
212       if (lists != null){
213          if (lists.length > 0){
214             log.warn("There's more than one mailing list for event '" + eventKey + "' (" + lists.length + " lists )");
215             log.warn("Choosing the first list: " + lists[0].getName());
216          }
217          return lists[0];
218       }
219       return null;
220    }
221 
222    /**
223     * Connect to remote reporting service and retrieve subscribers
224     * @param list The mailing list to retrieve subscribers for
225     * @return An array of list  subscribers
226     */
227    protected RemoteSubscriber[] retrieveSubscribers(RemoteMailingList list) throws Exception{
228       // Just retrieve service and the subscribers.
229       ReportingService service = retrieveReportingService();
230       return service.getSubscribers(list);
231    }
232 
233    /**
234     * Helper method for retrieving remote ReportingService. ReportingService is defined
235     * on synchronous side of application and notifiers are expected to run on asynchronous
236     * side of application. So we are using the <code>BootstrapManager.getOtherSideUrl()</code>
237     * as the root of remote service url.
238     * @throws InfrastructureException if BoostrapManager and url cannot be retrieved
239     * @throws RemoteException if remote service cannot be retievied
240     * @return The retievied remote ReportingService
241     * @see org.figure8.join.core.setup.BootstrapManager
242     */
243    protected ReportingService retrieveReportingService() throws InfrastructureException, RemoteException{
244       // Prepare objects we need.
245       String connectionUrl = null;
246       ReportingService service = null;
247       try{
248          // Get bootstrap manager from container context if possible.
249          ContainerContextHandler handler = ContainerContextHandler.getInstance();
250          log.debug("ContainerContextHandler is available");
251          BootstrapManager manager = (BootstrapManager)handler.getComponent("bootstrapManager");
252          connectionUrl = manager.getOtherSideUrl();
253          connectionUrl += "/remoting/hessian/ReportingService";
254       }
255       catch (Exception e){
256          // Log and propagate as an infrastructure exception.
257          log.error("Exception while retrieving BootstrapManager. Maybe application is not correctly configured ?");
258          log.error("Here's the detailed message: " + e.getMessage());
259          throw new InfrastructureException("Exception while retrieving BootstrapManager", e);
260       }
261       try{
262          // Connect and retrieve Hessian proxy.
263          HessianProxyFactory proxyFactory = new HessianProxyFactory();
264          service = (ReportingService)proxyFactory.create(ReportingService.class, connectionUrl);
265          return service;
266       }
267       catch (Exception e){
268          // Log and propagate as a remote access exception?
269          log.error("Exception while connecting to remote ReportignService: " + e.getMessage());
270          throw new RemoteException("Exception while connecting to remote ReportingService", e);
271       }
272    }
273 }