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.util.*;
20  
21  /**
22   * A MappingStrategy that is configured via a resource bundle.<p>
23   * The resource bundle contains the script part of the url as key and the fully
24   * qualified class name of the corresponding AgiScript as value.<p>
25   * Example:
26   * 
27   * <pre>
28   * leastcostdial.agi = com.example.fastagi.LeastCostDialAgiScript
29   * hello.agi = com.example.fastagi.HelloAgiScript
30   * </pre>
31   * 
32   * LeastCostDialAgiScript and HelloAgiScript must both implement the AgiScript
33   * interface and have a default constructor with no parameters.<p>
34   * The resource bundle (properties) file is called
35   * <code>fastagi-mapping.properties</code> by default and must be available on 
36   * the classpath.
37   * 
38   * @author srt
39   * @version $Id$
40   */
41  public class ResourceBundleMappingStrategy extends AbstractMappingStrategy
42  {
43      private static final String DEFAULT_RESOURCE_BUNDLE_NAME = "fastagi-mapping";
44      private String resourceBundleName;
45      private Map<String, String> mappings;
46      private Map<String, AgiScript> instances;
47      private boolean shareInstances;
48  
49      /**
50       * Creates a new ResourceBundleMappingStrategy using shared instances..
51       */
52      public ResourceBundleMappingStrategy()
53      {
54          this(DEFAULT_RESOURCE_BUNDLE_NAME);
55      }
56  
57      /**
58       * Creates a new ResourceBundleMappingStrategy with the given basename
59       * of the resource bundle to use.
60       * 
61       * @param resourceBundleName basename of the resource bundle to use
62       */
63      public ResourceBundleMappingStrategy(String resourceBundleName)
64      {
65          this(resourceBundleName, true);
66      }
67  
68      /**
69       * Creates a new ResourceBundleMappingStrategy indicating whether to use shared
70       * instances or not.
71       * 
72       * @param shareInstances <code>true</code> to use shared instances,
73       *                       <code>false</code> to create a new instance for
74       *                       each request.
75       * @since 0.3
76       */
77      public ResourceBundleMappingStrategy(boolean shareInstances)
78      {
79          this(DEFAULT_RESOURCE_BUNDLE_NAME, shareInstances);
80      }
81  
82      /**
83       * Creates a new ResourceBundleMappingStrategy with the given basename
84       * of the resource bundle to use and indicating whether to use shared
85       * instances or not.
86       * 
87       * @param resourceBundleName basename of the resource bundle to use
88       * @param shareInstances <code>true</code> to use shared instances,
89       *                       <code>false</code> to create a new instance for
90       *                       each request.
91       * @since 0.3
92       */
93      public ResourceBundleMappingStrategy(String resourceBundleName, boolean shareInstances)
94      {
95          super();
96          this.resourceBundleName = resourceBundleName;
97          this.shareInstances = shareInstances;
98      }
99  
100     /**
101      * Sets the basename of the resource bundle to use.<p>
102      * Default is "fastagi-mapping".
103      * 
104      * @param resourceBundleName basename of the resource bundle to use
105      */
106     public void setResourceBundleName(String resourceBundleName)
107     {
108         this.resourceBundleName = resourceBundleName;
109         synchronized (this)
110         {
111             this.mappings = null;
112             this.instances = null;
113         }
114     }
115 
116     /**
117      * Sets whether to use shared instances or not. If set to <code>true</code>
118      * all AgiRequests are served by the same instance of an
119      * AgiScript, if set to <code>false</code> a new instance is created for
120      * each request.<p>
121      * Default is <code>true</code>.
122      * 
123      * @param shareInstances <code>true</code> to use shared instances,
124      *                       <code>false</code> to create a new instance for
125      *                       each request.
126      * @since 0.3
127      */
128     public synchronized void setShareInstances(boolean shareInstances)
129     {
130         this.shareInstances = shareInstances;
131     }
132 
133     private synchronized void loadResourceBundle()
134     {
135         ResourceBundle resourceBundle;
136         Enumeration<?> keys;
137 
138         mappings = new HashMap<String, String>();
139         if (shareInstances)
140         {
141             instances = new HashMap<String, AgiScript>();
142         }
143 
144         try
145         {
146             resourceBundle = ResourceBundle.getBundle(resourceBundleName, Locale.getDefault(), getClassLoader());
147         }
148         catch (MissingResourceException e)
149         {
150             logger.info("Resource bundle '" + resourceBundleName + "' not found.");
151             return;
152         }
153 
154         keys = resourceBundle.getKeys();
155 
156         while (keys.hasMoreElements())
157         {
158             String scriptName;
159             String className;
160             AgiScript agiScript;
161 
162             scriptName = (String) keys.nextElement();
163             className = resourceBundle.getString(scriptName);
164 
165             mappings.put(scriptName, className);
166 
167             if (shareInstances)
168             {
169                 agiScript = createAgiScriptInstance(className);
170                 if (agiScript == null)
171                 {
172                     continue;
173                 }
174                 instances.put(scriptName, agiScript);
175             }
176 
177             logger.info("Added mapping for '" + scriptName + "' to class " + className);
178         }
179     }
180 
181     public synchronized AgiScript determineScript(AgiRequest request)
182     {
183         if (mappings == null || (shareInstances && instances == null))
184         {
185             loadResourceBundle();
186         }
187 
188         if (shareInstances)
189         {
190             return instances.get(request.getScript());
191         }
192         else
193         {
194             return createAgiScriptInstance(mappings.get(request.getScript()));
195         }
196     }
197 }