View Javadoc

1   // 
2   // Copyright (c) 2003, Caltha - Gajda, Krzewski, Mach, Potempski Sp.J. 
3   // All rights reserved. 
4   //   
5   // Redistribution and use in source and binary forms, with or without modification,  
6   // are permitted provided that the following conditions are met: 
7   //   
8   // * Redistributions of source code must retain the above copyright notice,  
9   // this list of conditions and the following disclaimer. 
10  // * Redistributions in binary form must reproduce the above copyright notice,  
11  // this list of conditions and the following disclaimer in the documentation  
12  // and/or other materials provided with the distribution. 
13  // * Neither the name of the Caltha - Gajda, Krzewski, Mach, Potempski Sp.J.  
14  // nor the names of its contributors may be used to endorse or promote products  
15  // derived from this software without specific prior written permission. 
16  //
17  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"  
18  // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED  
19  // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
20  // IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,  
21  // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,  
22  // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 
23  // OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
24  // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)  
25  // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE  
26  // POSSIBILITY OF SUCH DAMAGE. 
27  //
28  package org.objectledge.web.mvc.finders;
29  
30  import java.util.HashMap;
31  
32  import org.jcontainer.dna.Logger;
33  import org.objectledge.pipeline.Valve;
34  import org.objectledge.templating.Template;
35  import org.objectledge.templating.TemplateNotFoundException;
36  import org.objectledge.templating.Templating;
37  import org.objectledge.web.mvc.builders.Builder;
38  import org.objectledge.web.mvc.components.Component;
39  import org.picocontainer.MutablePicoContainer;
40  
41  /***
42   * Implementation of MVC finding services.
43   * 
44   * @author <a href="mailto:dgajda@caltha.pl">Damian Gajda</a>
45   * @version $Id: MVCFinder.java,v 1.36 2005/07/29 11:57:18 rafal Exp $
46   */
47  public class MVCFinder implements MVCTemplateFinder, MVCClassFinder
48  {
49      /***
50       * Different kinds of UI elements handled by the finder.
51       */
52      protected enum Kind
53      {
54          /*** View element. */
55          VIEW("views"),
56          /*** Action element. */
57          ACTION("actions"),
58          /*** Component element. */
59          COMPONENT("components");
60          
61          private Kind(String infix)
62          {
63              this.infix = infix;
64          }
65          
66          private final String infix;
67          
68          /***
69           * Returns the path infix used by name sequences.
70           * 
71           * @return the path infix used by name sequences.
72           */
73          public String getInfix()
74          {
75              return infix;
76          }
77      }
78      
79  	/**/package-summary/html">Internal constant for choosing "views" package name part/ *//package-summary.html">* /package-summary.html">Internal constant for choosing "views" package name part. */
80  	private static final String VIEWS = "views";
81  	/**/package-summary/html">Internal constant for choosing "actions" package name part/ *//package-summary.html">* /package-summary.html">Internal constant for choosing "actions" package name part. */
82  	private static final String ACTIONS = "actions";
83  	/**/package-summary/html">Internal constant for choosing "components" package name part/ *//package-summary.html">* /package-summary.html">Internal constant for choosing "components" package name part. */
84  	private static final String COMPONENTS = "components";
85  	
86  	private MutablePicoContainer container;
87  	
88      /*** the logger. */
89      private Logger logger;
90      
91      /*** The Templating component. */
92      private Templating templating;
93  	
94      /*** The name sequence factory. */
95      private NameSequenceFactory nameSequenceFactory;
96      
97      /*** The class instances cache */
98      private HashMap<String, Object> classInstanceCache = new HashMap<String, Object>();
99  
100     /*** Special marker object for the classInstanceCache */
101     private static final Object MISSING = new Object();    
102     
103     /***
104      * Creates a MVCFinder component.
105      * 
106      * @param container the container to store loaded classes.
107      * @param logger the logger to use.
108      * @param templating the templating component.
109      * @param nameSequenceFactory the name sequence factory component.
110      */
111 	public MVCFinder(MutablePicoContainer container, Logger logger, Templating templating, 
112         NameSequenceFactory nameSequenceFactory)
113 	{
114 		this.container = container;
115         this.logger = logger;
116         this.templating = templating;
117         this.nameSequenceFactory = nameSequenceFactory;
118 	}
119 
120 	// templates ////////////////////////////////////////////////////////////////////////////////
121 
122     // builder templates ////////////////////////////////////////////////////////////////////////
123 
124   	/***
125 	 * {@inheritDoc}
126 	 */
127     public MVCTemplateFinder.Result findBuilderTemplate(String view)
128     {
129 		return findBuilderTemplate(view, "findBuilderTemplate");
130     }
131 
132 	// component templates ////////////////////////////////////////////////////////////////////////
133 
134 	/***
135 	 * {@inheritDoc}
136 	 */
137 	public Template getComponentTemplate(String name)
138 	{
139         return findTemplate(Kind.COMPONENT, name, false, "getComponentTemplate");
140 	}
141 
142 	// actions //////////////////////////////////////////////////////////////////////////////////
143 
144 	/***
145 	 * {@inheritDoc}
146 	 */
147 	public Valve getAction(String actionName)
148 	{
149 		return (Valve)findObject(Kind.ACTION, actionName, false, "getAction");
150 	}
151 
152     // builders /////////////////////////////////////////////////////////////////////////////////
153 
154     /***
155      * {@inheritDoc}
156      */
157     public MVCClassFinder.Result findBuilder(String view)
158     {
159         return findBuilder(view, "findBuilder");
160     }
161 
162 	/***
163 	 * {@inheritDoc}
164 	 */
165     public String findEnclosingViewName(String viewName)
166     {
167         if(viewName != null && viewName.length() != 0)
168         {
169             Sequence classSequence = nameSequenceFactory.
170                 getClassNameSequence(VIEWS, viewName, true, true);
171 
172             Sequence templateSequence = nameSequenceFactory.
173                 getTemplateNameSequence(VIEWS, viewName, true, true);
174 
175             while(classSequence.hasNext() && templateSequence.hasNext())
176             {
177                 String className = classSequence.next();
178                 String templateName = templateSequence.next();
179                 logger.debug("findEnclosingViewName: trying "+className+" and "+templateName);
180 
181                 if(getClassInstance(className) != null)
182                 {
183                     break;
184                 }
185 
186                 if(templating.templateExists(templateName))
187                 {
188                     break;
189                 }
190             }
191             
192             String classSequenceViewName = classSequence.currentView();
193             String templateSequenceViewName = templateSequence.currentView();
194             if((classSequenceViewName == templateSequenceViewName) // both nulls
195                || classSequenceViewName.equals(templateSequenceViewName))
196             {
197                 return classSequenceViewName;
198             }
199             else
200             {
201                 throw new IllegalStateException("Sequences produced different view names: "+
202                     classSequenceViewName+" (class sequence) "+
203                     templateSequenceViewName+" (template sequence)");
204             }
205         }
206         return null;
207     }
208 
209 	// components ///////////////////////////////////////////////////////////////////////////////
210 
211 	/***
212 	 * {@inheritDoc}
213 	 */
214 	public Component getComponent(String componentName)
215 	{
216 		return (Component)
217             findObject(Kind.COMPONENT, componentName, false, "getComponent");
218 	}    
219 
220     // implementation ///////////////////////////////////////////////////////////////////////////
221 
222 	private Template findTemplate(Kind kind, String templateName, boolean fallback,
223         String methodName)
224 	{
225 		if(templateName != null && templateName.length() != 0)
226 		{
227 			Sequence sequence = getTemplateNameSequence(kind, templateName, fallback, false);
228 			while(sequence.hasNext())
229 			{
230 				String name = sequence.next();
231 				logger.debug(methodName+": trying "+name);
232                 if(templating.templateExists(name))
233                 {
234                     try
235                     {
236                         return templating.getTemplate(name);
237                     }
238                     catch(TemplateNotFoundException e)
239                     {
240                         throw new IllegalStateException("Existing template disappeared", e);
241                     }
242                 }
243 			}
244 		}
245 		return null;
246 	}
247 
248     private MVCTemplateFinder.Result findBuilderTemplate(String templateName, String methodName)
249     {
250         if(templateName != null && templateName.length() != 0)
251         {
252             Sequence sequence = getTemplateNameSequence(Kind.VIEW, templateName, true, false);
253             while(sequence.hasNext())
254             {
255                 String name = sequence.next();
256                 logger.debug(methodName+": trying "+name);
257                 if(templating.templateExists(name))
258                 {
259                     try
260                     {
261                         Template template = templating.getTemplate(name);
262                         return new MVCTemplateFinder.Result(
263                             templateName, template, sequence.currentView());
264                     }
265                     catch(TemplateNotFoundException e)
266                     {
267                         throw new IllegalStateException("Existing template disappeared", e);
268                     }
269                 }
270             }
271             return new MVCTemplateFinder.Result(templateName, null, sequence.currentView());
272         }
273         return new MVCTemplateFinder.Result(templateName, null, null);
274     }
275 
276     /***
277      * Return a template lookup sequence.
278      * 
279      * @param kind the kind of template being looked up.
280      * @param templateName the view name.
281      * @param fallback perform fallback.
282      * @param enclosing obsolete paramter.
283      * @return a lookup sequence.
284      */
285     protected Sequence getTemplateNameSequence(Kind kind, String templateName,
286         boolean fallback, boolean enclosing)
287     {
288         return nameSequenceFactory.
289         	getTemplateNameSequence(kind.getInfix(), templateName, fallback, enclosing);
290     }
291 
292     private Object findObject(Kind kind, String className, boolean fallback, String methodName)
293 	{
294 		if(className != null && className.length() != 0)
295 		{
296 			Sequence sequence = nameSequenceFactory.
297 				getClassNameSequence(kind.getInfix(), className, fallback, false);
298 			while(sequence.hasNext())
299 			{
300 				String name = sequence.next();
301 				logger.debug(methodName+": trying "+name);
302 				Object obj = getClassInstance(name);
303                 if(obj != null)
304                 {
305                     return obj;
306                 }
307 			}
308 		}
309 		return null;
310 	}
311 
312     private MVCClassFinder.Result findBuilder(String className, String methodName)
313     {
314         if(className != null && className.length() != 0)
315         {
316             Sequence sequence = nameSequenceFactory.
317                 getClassNameSequence(Kind.VIEW.getInfix(), className, true, false);
318             while(sequence.hasNext())
319             {
320                 String name = sequence.next();
321                 logger.debug(methodName+": trying "+name);
322                 Object obj = getClassInstance(name);
323                 if(obj != null)
324                 {
325                     return new MVCClassFinder.Result(className, (Builder)obj, sequence
326                         .currentView());
327                 }
328             }
329             return new MVCClassFinder.Result(className, (Builder) null, sequence.currentView());
330         }
331         return new MVCClassFinder.Result(className, (Builder) null, null);
332     }
333     
334     private Object getClassInstance(String className)
335     {
336         Object instance;
337         synchronized(classInstanceCache)
338         {
339             instance = classInstanceCache.get(className);
340             if(instance == MISSING)
341             {
342                 return null;
343             }
344             if(instance == null)
345             {
346                 try
347                 {
348                     Class clazz = Class.forName(className);
349                     if(container.getComponentAdapter(clazz) == null)
350                     {
351                         container.registerComponentImplementation(clazz);
352                     }
353                     instance = container.getComponentInstance(clazz);
354                     classInstanceCache.put(className, instance);
355                 }
356                 catch(ClassNotFoundException e)
357                 {
358                     classInstanceCache.put(className, MISSING);
359                     return null;
360                 }
361             }
362             return instance;
363         }
364     }
365 }