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.scripting;
16  
17  import org.figure8.join.core.Configurable;
18  import org.figure8.join.core.EntityObject;
19  import org.figure8.join.core.ParameterDefinition;
20  import org.figure8.join.core.InvalidParameterException;
21  import org.figure8.join.core.messaging.JMSConsumerBean;
22  import org.figure8.join.services.properties.PropertiesExtractor;
23  import org.figure8.join.util.LogUtil;
24  
25  import org.apache.commons.logging.Log;
26  
27  import javax.jms.Message;
28  import javax.jms.ObjectMessage;
29  
30  import java.io.File;
31  import java.io.FileOutputStream;
32  import java.io.FileNotFoundException;
33  import java.util.Date;
34  import java.util.List;
35  import java.util.ArrayList;
36  import java.util.Properties;
37  /**
38   * This is a base class for JMS consumers that wants to launch scripts
39   * when a new message arrive. It acts as an adapter between the JMS world
40   * and the {@link ScriptLauncher} facilities.
41   * <br/>
42   * This class is a JMSConsumerBean that is {@link Configurable} : it defines
43   * an optional parameter that should be a {@link PropertiesExtractor} impl.
44   * This extractor help tha transition from a JMS view (that is object message
45   * based) to a general script view (that is properties and arguments based).
46   * <br/>
47   * Extensions of this class should specifiy which ScriptLauncher implementation
48   * to use when running scripts.
49   *
50   * @see org.figure8.join.core.Configurable
51   * @see org.figure8.join.core.messaging.JMSConsumerBean
52   * @see org.figure8.join.services.properties.PropertiesExtractor
53   *
54   * @author <a href="mailto:laurent.broudoux@free.fr">Laurent Broudoux</a>
55   * @version $Revision: 1.2 $
56   */
57  public abstract class ScriptLauncherJMSAdapter extends ScriptLauncherAdapterSupport implements JMSConsumerBean{
58  
59     // Static -------------------------------------------------------------------
60  
61     /** Get a commons logger. */
62     private static final Log log = LogUtil.getLog(ScriptLauncherJMSAdapter.class);
63  
64     /** Name of configurable parameter denoting the propertiesExtractor to use for getting props. */
65     public static final String EXTRACTOR_PARAM = "propertiesExtractor";
66  
67     /** List of {@link ParameterDefinition}s supported by this adapter */
68     protected static List parameters = new ArrayList();
69  
70     /** ParameterDefinition representation of parameter denoting the propertiesExtractor to use. */
71     protected static final ParameterDefinition extractionParam = new ParameterDefinition(EXTRACTOR_PARAM,
72             "The PropertiesExtractor implementation to use", "org.figure8.join.services.properties.DefaultPropertiesExtractor", true);
73  
74  
75     // Attributes ---------------------------------------------------------------
76  
77     /** The class name properties extractor implementation to use. */
78     private String extractorClass;
79     /** The PropertiesExtractor implementation to use. */
80     private PropertiesExtractor extractor = null;
81  
82  
83     // Public -------------------------------------------------------------------
84  
85     /**
86      * Specify the class of PropertiesExtractor implementation to use
87      * @param extractorClass The FQN of Java class representing PropertiesExtractor impl
88      * @throws InvalidParameterException if <b>extractorClass</b> is not found or does
89      * not implement the PropertiesExtractor interface
90      */
91     public void setPropertiesExtractorClass(String extractorClass) throws InvalidParameterException{
92        this.extractorClass = extractorClass;
93        // Try instantiating properties extractor now.
94        instantiatePropertiesExtractor();
95     }
96  
97  
98     // Implementation of JMSConsumerBean ----------------------------------------
99  
100    /**
101     * This method is executed on message delivery. This implementation only
102     * process message of type ObjectMessage. The process is the following :<br/>
103     * first: retrieve object from message and eventually extract its properties,<br/>
104     * @param message
105     */
106    public void onMessage(Message message){
107       if (log.isInfoEnabled())
108          log.info("Message received by ScriptLauncherJMSAdapter '" + name + "'");
109       File logFile = null;
110       ScriptLogInfo logInfo = null;
111 
112       // Process only the ObjectMessage.
113       if (message instanceof ObjectMessage){
114          // Retrieve object from message.
115          Object obj = null;
116          try {obj = ((ObjectMessage)message).getObject();}
117          catch (Exception e){
118             log.fatal("Exception while extracting object from JMSMessage into '" + getName() + "'");
119             log.fatal("Here's the detailed message: " + e.getMessage());
120             return;
121          }
122          // Prepare & extract runtime properties.
123          Properties props = new Properties();
124          if (extractor != null){
125             try {props.putAll(extractor.extract(obj));}
126             catch (InvalidParameterException ipe){
127                log.error("Exception while extracting properties from object into '" + getName() + "'");
128                log.error("Here's the detailed message: " + ipe.getMessage());
129             }
130             if (log.isDebugEnabled())
131                log.debug("Launching script with properties: " + props);
132          }
133          // Prepare log and info if possible (ie: we are working on an entity).
134          if (obj instanceof EntityObject){
135             // Initialize script log info.
136             logFile = createNewLogFile();
137             logInfo = new ScriptLogInfo((EntityObject)obj, logFile.getPath().replace('\\', '/'),
138                     name, "JMSAdapter", getScriptLauncher().getScriptPath());
139          }
140 
141          try{
142             // Launching script (log start time).
143             if (log.isInfoEnabled())
144                log.info("Launching the script of '" + name + "' JMS adapter. Start time is: " + new Date());
145             // Set the log outputstream and run the script !
146             getScriptLauncher().setLogOutputStream(new FileOutputStream(logFile));
147             getScriptLauncher().runScript(props);
148             // Log the execution result.
149             if (logInfo != null)
150                logInfo.setExceptionMsg("Execution is properly terminated.");
151          }
152          catch (ScriptException se){
153             // Store and log exception msg.
154             log.error("ScriptException when running " + getScriptLauncher().getScriptPath() + ": " + se.getMessage());
155             if (logInfo != null)
156                logInfo.setExceptionMsg(se.getMessage());
157          }
158          catch (FileNotFoundException fnfe){
159             // Store and log the exception.
160             log.error("FileNotFoundException while getting OS on " + logFile.getPath() + ": " + fnfe.getMessage());
161             if (logInfo != null)
162                logInfo.setExceptionMsg(fnfe.getMessage());
163          }
164          finally{
165             // Log end date.
166             if (log.isInfoEnabled())
167                log.info("Script of '" + name + "' JMS adapter has end. Stop time is: " + new Date());
168          }
169 
170          if (logInfo != null){
171             boolean done = saveLogInfoIfAvailable(logInfo);
172          }
173       }
174       return;
175    }
176 
177    /**
178     * Implement this method to stop current process and free resources.
179     * This method should not throw exceptions.
180     */
181    public void stop(){
182       log.info("Stopping the ScriptLauncherJMSAdapter named '" + name + "'...");
183    }
184 
185 
186    // Implementation of Configurable -------------------------------------------
187 
188    /**
189     * Get this object parameters definitions as a list
190     * @return A list of {@code ParameterDefinition} objects
191     */
192    public List getParameterDefinitionsAsList(){
193       // Use script launcher parameters as base.
194       if (parameters.isEmpty()){
195          parameters.addAll(getScriptLauncher().getParameterDefinitionsAsList());
196          parameters.add(extractionParam);
197       }
198       return parameters;
199    }
200 
201    /**
202     * Set the value of a parameter using its name
203     * @param parameterName The name of parameter so set value for
204     * @param parameterValue The value of the paramater
205     * @throws InvalidParameterException if this parameter is not supported by this object
206     */
207    public void setParameter(String parameterName, String parameterValue) throws InvalidParameterException{
208       try{
209          // Delegate to super class first.
210          super.setParameter(parameterName, parameterValue);
211       }
212       catch (InvalidParameterException ipe){
213          // Then test the managed parameter.
214          if (EXTRACTOR_PARAM.equals(parameterName))
215             setPropertiesExtractorClass(parameterValue);
216          else{
217             log.error("The parameter '" + parameterName + "' is not supported by ScriptLauncherJMSAdapter");
218             throw new InvalidParameterException("The parameter '" + parameterName + "' is not supported by ScriptLauncherJMSAdapter");
219          }
220       }
221    }
222 
223 
224    // Private ------------------------------------------------------------------
225 
226    /**
227     * Try to instantiate the <code>PropertieExtractor</code> associated with this adapter
228     * @throws InvalidParameterException if the <b>extractorClass</b> inner field is not valid
229     */
230    private void instantiatePropertiesExtractor() throws InvalidParameterException{
231       if (extractorClass != null && extractor == null){
232          try{
233             // Load class from context class loader and retrieve new instance.
234             Class clazz = Thread.currentThread().getContextClassLoader().loadClass(extractorClass);
235             extractor = (PropertiesExtractor)clazz.newInstance();
236          }
237          catch (Exception e){
238             // Log and wrap within an InvalidParameterException.
239             log.error("Exception while trying to instantiate extractor for ScriptLauncherJMSAdapter '" + name + "'");
240             log.error("Here's the exception message : " + e.getMessage());
241             throw new InvalidParameterException("'" + extractorClass +
242                     "' cannot be found or does not implement PropertiesExtractor", e);
243          }
244       }
245    }
246 }