View Javadoc

1   /*
2    *  Copyright 2004-2006 Stefan Reuter
3    *
4    *  Licensed under the Apache License, Version 2.0 (the "License");
5    *  you may not use this file except in compliance with the License.
6    *  You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License.
15   *
16   */
17  package org.asteriskjava.fastagi;
18  
19  import java.lang.reflect.Constructor;
20  import java.net.URL;
21  import java.net.URLClassLoader;
22  import java.net.MalformedURLException;
23  import java.util.List;
24  import java.util.ArrayList;
25  import java.io.File;
26  
27  import org.asteriskjava.util.Log;
28  import org.asteriskjava.util.LogFactory;
29  
30  /**
31   * Abstract base class for common mapping strategies.
32   * <p/>
33   * If you implement your own mapping strategy you can derive from this class.
34   *
35   * @author srt
36   * @since 0.3
37   */
38  public abstract class AbstractMappingStrategy implements MappingStrategy
39  {
40      /**
41       * Reference to Asterisk-Java's logging subsystem.
42       */
43      protected Log logger = LogFactory.getLog(getClass());
44      private static final String[] DEFAULT_SCRIPT_PATH = new String[]{"agi"};
45      
46      private ClassLoader defaultClassLoader = null;
47  
48      @Override
49      public AgiScript determineScript(AgiRequest request, AgiChannel channel)
50      {
51          return determineScript(request);
52      }
53  
54      public abstract AgiScript determineScript(AgiRequest request);
55  
56      /**
57       * Returns the ClassLoader to use for loading AgiScript classes and load
58       * other resources like the mapping properties file.<p>
59       * By default this method returns a class loader that searches for classes in the
60       * "agi" subdirectory (if it exists) and uses the context class loader of the
61       * current thread as the parent class loader.<p>
62       * You can override this method if you prefer using a different class loader.
63       *
64       * @return the ClassLoader to use for loading AgiScript classes and load
65       *         other resources like the mapping properties file.
66       * @since 1.0.0
67       */
68      protected synchronized ClassLoader getClassLoader()
69      {
70          if (defaultClassLoader == null)
71          {
72              final ClassLoader parentClassLoader = Thread.currentThread().getContextClassLoader();
73              final List<URL> dirUrls = new ArrayList<URL>();
74  
75              for (String scriptPathEntry : DEFAULT_SCRIPT_PATH)
76              {
77                  final File scriptDir = new File(scriptPathEntry);
78                  if (! scriptDir.isDirectory())
79                  {
80                      continue;
81                  }
82  
83                  try
84                  {
85                      dirUrls.add(scriptDir.toURI().toURL());
86                  }
87                  catch (MalformedURLException e)
88                  {
89                      // should not happen
90                  }
91              }
92  
93              if (dirUrls.size() == 0)
94              {
95                  return parentClassLoader;
96              }
97  
98              defaultClassLoader = new URLClassLoader(dirUrls.toArray(new URL[dirUrls.size()]), parentClassLoader);
99          }
100 
101         return defaultClassLoader;
102     }
103 
104     /**
105      * Creates a new instance of an AGI script.
106      *
107      * @param className Class name of the AGI script. The class must implement
108      *                  {@link AgiScript}.
109      * @return the created instance of the AGI script class. If the instance
110      *         can't be created an error is logged and <code>null</code> is
111      *         returned.
112      */
113     @SuppressWarnings("unchecked")
114     protected AgiScript createAgiScriptInstance(String className)
115     {
116         Class<?> tmpClass;
117         Class<AgiScript> agiScriptClass;
118         Constructor<AgiScript> constructor;
119         AgiScript agiScript;
120 
121         agiScript = null;
122 
123         try
124         {
125             tmpClass = getClassLoader().loadClass(className);
126         }
127         catch (ClassNotFoundException e1)
128         {
129             logger.debug("Unable to create AgiScript instance of type " + className
130                     + ": Class not found, make sure the class exists and is available on the CLASSPATH");
131             return null;
132         }
133 
134         if (!AgiScript.class.isAssignableFrom(tmpClass))
135         {
136             logger.warn("Unable to create AgiScript instance of type " + className
137                     + ": Class does not implement the AgiScript interface");
138             return null;
139         }
140 
141         agiScriptClass = (Class<AgiScript>) tmpClass;
142         try
143         {
144             constructor = agiScriptClass.getConstructor();
145             agiScript = constructor.newInstance();
146         }
147         catch (Exception e)
148         {
149             logger.warn("Unable to create AgiScript instance of type " + className, e);
150         }
151 
152         return agiScript;
153     }
154 }