001    /*
002      Copyright (C) 2002-2003 Laurent Martelli <laurent@aopsys.com>
003                              Renaud Pawlak <renaud@aopsys.com>
004      
005      This program is free software; you can redistribute it and/or modify
006      it under the terms of the GNU Lesser General Public License as
007      published by the Free Software Foundation; either version 2 of the
008      License, or (at your option) any later version.
009    
010      This program is distributed in the hope that it will be useful, but
011      WITHOUT ANY WARRANTY; without even the implied warranty of
012      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013      Lesser General Public License for more details.
014    
015      You should have received a copy of the GNU Lesser General Public
016      License along with this program; if not, write to the Free Software
017      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
018      USA */
019    
020    package org.objectweb.jac.aspects.gui;
021    
022    import java.util.Arrays;
023    import java.util.Hashtable;
024    import org.apache.log4j.Level;
025    import org.apache.log4j.Logger;
026    import org.objectweb.jac.core.ACConfiguration;
027    import org.objectweb.jac.core.Imports;
028    import org.objectweb.jac.core.NameRepository;
029    import org.objectweb.jac.core.rtti.AbstractMethodItem;
030    import org.objectweb.jac.core.rtti.ClassItem;
031    import org.objectweb.jac.core.rtti.ClassRepository;
032    import org.objectweb.jac.core.rtti.FieldItem;
033    import org.objectweb.jac.util.ExtArrays;
034    
035    /**
036     * This is a generic view factory. It can be configured to use any
037     * constructor to build views of any type.
038     */
039    public class ViewFactory {
040        static Logger logger = Logger.getLogger("gui.factory");
041    
042        static Imports imports = new Imports();
043    
044        static {
045            imports.add("org.objectweb.jac.aspects.gui.*");
046            imports.add("org.objectweb.jac.core.rtti.*");
047            imports.add("java.lang.*");        
048        }
049    
050        /**
051         * Init a swing factory by setting the constuctor types. 
052         */ 
053        public static void init(String type, ViewFactory f) {
054            f.setViewConstructor("Object", "GenericFactory.createObjectView");
055            f.setViewConstructor("NoTab", "GenericFactory.createObjectViewNoTab");
056            f.setViewConstructor ("InputParameters", "GenericFactory.createParameters");
057            //      f.setViewConstructor("java.lang.Throwable", "ExceptionViewer.createExceptionViewer");
058            if (type.equals("swing")) {
059                f.setViewConstructor("ObjectView","swing.ObjectView");
060                f.setViewConstructor("Customized", "swing.SwingCustomized");
061                f.setViewConstructor("Reference", "swing.ReferenceView(Object,Object,FieldItem)");
062                f.setViewConstructor("ObjectChooser", "swing.ObjectChooser");
063                f.setViewConstructor("Tree", "swing.Tree");
064                f.setViewConstructor("Panel", "swing.SwingPanelView");
065                f.setViewConstructor("Label", "swing.SwingLabel");
066                f.setViewConstructor("Tabbed", "swing.SwingTabbedView");
067                f.setViewConstructor("ParameterContainer", "swing.SwingEditorContainer");
068                f.setViewConstructor("Container", "swing.SwingContainerView");
069                f.setViewConstructor("SingleSlotContainer", "swing.SingleSlotContainer");
070                f.setViewConstructor("Desktop", "swing.DesktopView");
071                f.setViewConstructor("Method", "swing.SwingMethodView");
072                f.setViewConstructor("Field", "swing.SwingFieldView");
073                f.setViewConstructor("Enum", "swing.EnumViewer(Object,Object,FieldItem)");
074                f.setViewConstructor("Table", "swing.SwingTableView");
075                f.setViewConstructor("List", "swing.List");
076                f.setViewConstructor("Dialog", "swing.Dialog");
077                f.setViewConstructor("MenuBar", "swing.MenuBar()");
078                f.setViewConstructor("Menu", "swing.Menu()");
079                f.setViewConstructor("ToolBar", "swing.ToolBar");
080                f.setViewConstructor("StatusBar", "swing.StatusBar");
081    
082                f.setViewConstructor("Empty", "swing.SwingEmptyView");
083      
084                f.setViewConstructor("dateHour", "swing.DateHourViewer(Object,Object,FieldItem)");
085                f.setViewConstructor("timestamp", "swing.TimestampViewer(Object,Object,FieldItem)");
086                f.setViewConstructor("java.util.Date", "swing.DateViewer(Object,Object,FieldItem)");
087                f.setViewConstructor("imageURL", "swing.ImageURLViewer(java.net.URL,Object,FieldItem)");
088                f.setViewConstructor("image", "swing.ImageViewer(byte[],Object,FieldItem)");
089                f.setViewConstructor("text", "swing.TextViewer(Object,Object,FieldItem)");
090                f.setViewConstructor("Float","swing.FloatViewer(Object,Object,FieldItem)");
091                f.setViewConstructor("Double","swing.FloatViewer(Object,Object,FieldItem)");
092                f.setViewConstructor("double","swing.FloatViewer(Object,Object,FieldItem)");
093                f.setViewConstructor("float","swing.FloatViewer(Object,Object,FieldItem)");
094                f.setViewConstructor("percentage","swing.PercentViewer(Object,Object,FieldItem)");
095                f.setViewConstructor("editor:percentage","swing.PercentEditor(Object,FieldItem)");
096    
097                f.setViewConstructor("org.objectweb.jac.lib.Attachment", "swing.AttachmentViewer(Object,Object,FieldItem)");
098    
099                //editors
100                f.setViewConstructor("editor:java.lang.Boolean", "swing.BooleanEditor");
101                f.setViewConstructor("editor:boolean", "swing.BooleanEditor");
102                f.setViewConstructor("editor:java.io.File", "swing.FileEditor");
103                f.setViewConstructor("editor:filePath", "swing.FilePathEditor");
104                f.setViewConstructor("editor:org.objectweb.jac.util.File", "swing.FileEditor");
105                f.setViewConstructor("editor:directory", "swing.DirectoryEditor");
106                f.setViewConstructor("editor:java.net.URL", "swing.URLEditor");
107                f.setViewConstructor("editor:java.util.Date", "swing.DateEditor");
108                f.setViewConstructor("editor:java.awt.Point", "swing.PointEditor");
109                f.setViewConstructor("editor:dateHour", "swing.DateHourEditor");
110                f.setViewConstructor("editor:text", "swing.TextEditor");
111                f.setViewConstructor("editor:javaCode", "swing.JavaCodeEditor");
112                f.setViewConstructor("editor:password", "swing.PasswordFieldEditor");
113                f.setViewConstructor("editor:org.objectweb.jac.lib.Attachment", "swing.AttachmentEditor");
114                f.setViewConstructor("editor:java.lang.Float", "swing.FloatEditor");
115                f.setViewConstructor("editor:java.lang.Double", "swing.FloatEditor");
116                f.setViewConstructor("editor:java.lang.Integer", "swing.PrimitiveFieldEditor(Object,FieldItem)");
117                f.setViewConstructor("editor:java.lang.Long", "swing.PrimitiveFieldEditor(Object,FieldItem)");
118                f.setViewConstructor("editor:java.lang.Short", "swing.PrimitiveFieldEditor(Object,FieldItem)");
119                f.setViewConstructor("editor:java.lang.Character", "swing.PrimitiveFieldEditor(Object,FieldItem)");
120                f.setViewConstructor("editor:java.lang.Byte", "swing.PrimitiveFieldEditor(Object,FieldItem)");
121                f.setViewConstructor("editor:float", "swing.FloatEditor");
122                f.setViewConstructor("editor:double", "swing.FloatEditor");
123                f.setViewConstructor("editor:integer", "swing.PrimitiveFieldEditor(Object,FieldItem)");
124                f.setViewConstructor("editor:long", "swing.PrimitiveFieldEditor(Object,FieldItem)");
125                f.setViewConstructor("editor:short", "swing.PrimitiveFieldEditor(Object,FieldItem)");
126                f.setViewConstructor("editor:char", "swing.PrimitiveFieldEditor(Object,FieldItem)");
127                f.setViewConstructor("editor:java.lang.String", "swing.PrimitiveFieldEditor(Object,FieldItem)");
128                f.setViewConstructor("PrimitiveTypeEditor", "swing.PrimitiveFieldEditor(Object,FieldItem,boolean)");
129    
130                f.setViewConstructor("CollectionItemView", "swing.CollectionItemView");
131             
132                // table cells viewers
133                f.setViewConstructor("cell:java.util.Date", "swing.DateViewer()");
134                f.setViewConstructor("cell:dateHour", "swing.DateHourViewer()");
135                f.setViewConstructor("cell:timestamp", "swing.TimestampViewer()");
136                f.setViewConstructor("cell:imageURL", "swing.ImageURLViewer()");
137                f.setViewConstructor("cell:Reference", "swing.ReferenceView()");
138                f.setViewConstructor("cell:Enum", "swing.EnumViewer()");
139                f.setViewConstructor("cell:java.lang.Integer", "swing.IntViewer()");
140                f.setViewConstructor("cell:java.lang.Long", "swing.IntViewer()");
141                f.setViewConstructor("cell:int", "swing.IntViewer()");
142                f.setViewConstructor("cell:long", "swing.IntViewer()");
143                f.setViewConstructor("cell:java.lang.Float", "swing.FloatViewer()");
144                f.setViewConstructor("cell:java.lang.Double", "swing.FloatViewer()");
145                f.setViewConstructor("cell:float", "swing.FloatViewer()");
146                f.setViewConstructor("cell:double", "swing.FloatViewer()");
147                f.setViewConstructor("cell:percentage","swing.PercentViewer()");
148                f.setViewConstructor("cell:org.objectweb.jac.lib.Attachment", "swing.AttachmentViewer()");
149                f.setViewConstructor("cell:Method", "swing.SwingMethodView");
150                f.setViewConstructor("cell:java.lang.Boolean", "swing.BooleanViewer()");
151                f.setViewConstructor("cell:boolean", "swing.BooleanViewer()");
152                //f.setViewConstructor("cell:List", "swing.()");
153    
154            } else if(type.equals("web")) {
155             
156                f.setViewConstructor("ObjectView", "web.ObjectView");
157                f.setViewConstructor("Empty", "web.Empty");
158                f.setViewConstructor("Customized", "web.Customized");
159                f.setViewConstructor("Panel", "web.Panel");
160                f.setViewConstructor("Container", "web.Container");
161                f.setViewConstructor("SingleSlotContainer", "web.SingleSlotContainer");
162                f.setViewConstructor("Label", "web.Label");
163                f.setViewConstructor("Reference", "web.ReferenceView(Object,Object,FieldItem)");
164                f.setViewConstructor("Enum", "web.EnumViewer(Object,Object,FieldItem)");
165                f.setViewConstructor("Field", "web.PrimitiveField");
166                f.setViewConstructor("Table", "web.Table");
167                f.setViewConstructor("ChoiceCollection", "web.ChoiceCollection");
168                f.setViewConstructor("List", "web.List");
169                f.setViewConstructor("Tree", "web.Tree");
170                f.setViewConstructor("Tabbed", "web.Tabs");
171                f.setViewConstructor("Method", "web.Method");
172                f.setViewConstructor("EmbeddedMethod", "web.EmbeddedMethod");
173                f.setViewConstructor("Window", "web.Page");
174                f.setViewConstructor("RefreshWindow", "web.RefreshPage");
175                f.setViewConstructor("Dialog", "web.Dialog");
176                f.setViewConstructor("MenuBar", "web.MenuBar");
177                f.setViewConstructor("StatusBar", "web.StatusBar");
178                f.setViewConstructor("ToolBar", "web.ToolBar");
179                f.setViewConstructor("Menu", "web.Menu");
180    
181                f.setViewConstructor("dateHour", "web.DateHourViewer(Object,Object,FieldItem)");
182                f.setViewConstructor("timestamp", "web.TimestampViewer(Object,Object,FieldItem)");
183                f.setViewConstructor("java.util.Date", "web.DateViewer(Object,Object,FieldItem)");
184    
185                f.setViewConstructor("Float", "web.FloatViewer(Object,Object,FieldItem)");
186                f.setViewConstructor("Integer","web.IntViewer(Object,Object,FieldItem)");
187                f.setViewConstructor("Long","web.IntViewer(Object,Object,FieldItem)");
188                f.setViewConstructor("int","web.IntViewer(Object,Object,FieldItem)");
189                f.setViewConstructor("long","web.IntViewer(Object,Object,FieldItem)");
190                f.setViewConstructor("Double", "web.FloatViewer(Object,Object,FieldItem)");
191                f.setViewConstructor("float", "web.FloatViewer(Object,Object,FieldItem)");
192                f.setViewConstructor("double", "web.FloatViewer(Object,Object,FieldItem)");
193                f.setViewConstructor("percentage", "web.PercentViewer(Object,Object,FieldItem)");
194                f.setViewConstructor("org.objectweb.jac.util.Matrix", "web.MatrixView(Object,Object,FieldItem)");
195    
196                f.setViewConstructor("imageURL", "web.ImageURLViewer(Object,Object,FieldItem)");
197                f.setViewConstructor("text", "web.TextViewer");
198             
199                // table cells viewers
200                f.setViewConstructor("cell:imageURL", "web.ImageURLViewer()");
201                f.setViewConstructor("cell:java.util.Date", "web.DateViewer()");
202                f.setViewConstructor("cell:dateHour", "web.DateHourViewer()");
203                f.setViewConstructor("cell:timestamp", "web.TimestampViewer()");
204                f.setViewConstructor("cell:java.lang.Integer", "web.IntViewer()");
205                f.setViewConstructor("cell:java.lang.Long", "web.IntViewer()");
206                f.setViewConstructor("cell:int", "web.IntViewer()");
207                f.setViewConstructor("cell:long", "web.IntViewer()");
208                f.setViewConstructor("cell:java.lang.Float", "web.FloatViewer()");
209                f.setViewConstructor("cell:java.lang.Double", "web.FloatViewer()");
210                f.setViewConstructor("cell:float", "web.FloatViewer()");
211                f.setViewConstructor("cell:double", "web.FloatViewer()");
212                f.setViewConstructor("cell:percentage", "web.PercentViewer()");
213                f.setViewConstructor("cell:Reference", "web.ReferenceView()");
214                f.setViewConstructor("cell:Enum", "web.EnumViewer()");
215                f.setViewConstructor("cell:org.objectweb.jac.lib.Attachment", "web.AttachmentViewer()");
216                f.setViewConstructor("cell:java.util.List", "web.CompactList()");
217    
218                //editors
219                f.setViewConstructor("ParameterContainer", "web.EditorContainer");
220                f.setViewConstructor("PrimitiveTypeEditor", "web.PrimitiveFieldEditor(Object,FieldItem,boolean)");
221                f.setViewConstructor("ObjectChooser", "web.ObjectChooser");
222                f.setViewConstructor("IndexSelector", "web.IndexSelector");
223                f.setViewConstructor("IndicesSelector", "web.IndicesSelector");
224                f.setViewConstructor("editor:java.util.Date", "web.DateEditor");
225                f.setViewConstructor("editor:dateHour", "web.DateHourEditor");
226                f.setViewConstructor("editor:java.net.URL", "web.URLEditor");
227                f.setViewConstructor("editor:java.lang.Boolean", "web.BooleanEditor");
228                f.setViewConstructor("editor:boolean", "web.BooleanEditor");
229                f.setViewConstructor("editor:text", "web.TextEditor");
230                f.setViewConstructor("editor:javaCode", "web.TextEditor");
231                f.setViewConstructor("editor:password", "web.PasswordFieldEditor");
232                f.setViewConstructor("editor:java.lang.Float", "web.FloatEditor");
233                f.setViewConstructor("editor:java.lang.Double", "web.FloatEditor");
234                f.setViewConstructor("editor:java.lang.Integer", "web.PrimitiveFieldEditor(Object,FieldItem)");
235                f.setViewConstructor("editor:java.lang.Long", "web.PrimitiveFieldEditor(Object,FieldItem)");
236                f.setViewConstructor("editor:java.lang.Short", "web.PrimitiveFieldEditor(Object,FieldItem)");
237                f.setViewConstructor("editor:java.lang.Character", "web.PrimitiveFieldEditor(Object,FieldItem)");
238                f.setViewConstructor("editor:float", "web.FloatEditor");
239                f.setViewConstructor("editor:double", "web.FloatEditor");
240                f.setViewConstructor("cell:percentage", "web.PercentEditor(Object,FieldItem)");
241                f.setViewConstructor("editor:integer", "web.PrimitiveFieldEditor(Object,FieldItem)");
242                f.setViewConstructor("editor:long", "web.PrimitiveFieldEditor(Object,FieldItem)");
243                f.setViewConstructor("editor:short", "web.PrimitiveFieldEditor(Object,FieldItem)");
244                f.setViewConstructor("editor:char", "web.PrimitiveFieldEditor(Object,FieldItem)");
245                f.setViewConstructor("editor:java.lang.Byte", "web.PrimitiveFieldEditor(Object,FieldItem)");
246                f.setViewConstructor("editor:java.lang.String", "web.PrimitiveFieldEditor(Object,FieldItem)");
247                f.setViewConstructor("org.objectweb.jac.lib.Attachment", "web.AttachmentViewer(Object,Object,FieldItem)");
248                f.setViewConstructor("editor:org.objectweb.jac.lib.Attachment", "web.AttachmentEditor");
249                f.setViewConstructor("editor:java.io.Reader", "web.ReaderEditor");
250                f.setViewConstructor("editor:java.io.InputStream", "web.InputStreamEditor");
251    
252                f.setViewConstructor("CollectionItemView", "web.CollectionItemView");
253            }
254        }
255    
256        // viewType -> constructor
257        // views added in web.acc with setViewConstructor
258        Hashtable constructors = new Hashtable();
259    
260        /**
261         * Create a view of a given type.
262         *
263         * @param label the name of the view
264         * @param viewType the type of the view (for instance, "Object" or "Tree".
265         * @param params the parameters to pass to the view constructor
266         * @return a view of the demanded type.
267         */
268        public View createView(String label, String viewType, Object[] params,
269                               DisplayContext context) 
270            throws UnhandledViewTypeException
271        {
272            logger.debug("createView(\""+label+"\","+viewType+","+
273                      Arrays.asList(params)+")");
274            AbstractMethodItem constructor = 
275                (AbstractMethodItem)constructors.get(viewType);
276            if (constructor==null) {
277                throw new UnhandledViewTypeException(viewType);
278            }
279            logger.debug("  constructor = "+constructor.getLongName());
280            Object[] parameters;
281            Class[] paramTypes = constructor.getParameterTypes();
282            if (paramTypes.length>0 && paramTypes[0]==ViewFactory.class) {
283                logger.debug("  prepending factory to params");
284                if (paramTypes.length>1 && paramTypes[1]==DisplayContext.class) {
285                    logger.debug("  prepending context to params");
286                    parameters = new Object[params.length+2];
287                    System.arraycopy(params,0,parameters,2,params.length);
288                    parameters[0] = this;
289                    parameters[1] = context;
290                } else {
291                    parameters = new Object[params.length+1];
292                    System.arraycopy(params,0,parameters,1,params.length);
293                    parameters[0] = this;
294                }
295            } else {
296                parameters = params;
297            } 
298            logger.debug("  invoking constructor..."+Arrays.asList(parameters));
299            if (constructor.getParameterCount()!=parameters.length) {
300                throw new RuntimeException("Wrong number of arguments for "+
301                                           constructor.getLongName()+" ("+Arrays.asList(parameters)+")");
302            }
303            View result = (View)constructor.invoke(null,parameters);
304            result.setLabel(label);
305            result.setFactory(this);
306            result.setParameters(params);
307            result.setType(viewType);
308            result.setContext(context);
309            logger.debug("  createView("+viewType+","+label+") -> "+result);
310            return result;
311        }
312    
313        /**
314         * Convert Strings into the type expected by the view constructor.
315         */
316        public View createView(String label, String viewType, String[] params,
317                               DisplayContext context) 
318            throws UnhandledViewTypeException
319        {
320            logger.debug("createView(\""+label+"\","+viewType+","+
321                      Arrays.asList(params)+")");
322            AbstractMethodItem constructor = 
323                (AbstractMethodItem)constructors.get(viewType);
324            if (constructor==null) {
325                throw new UnhandledViewTypeException(viewType);
326            }
327            logger.debug("  constructor = "+constructor);
328            Class[] paramTypes = constructor.getParameterTypes();
329            Object[] args = new Object[params.length];
330            int offset = 0;
331            if (paramTypes.length>0 && paramTypes[0]==ViewFactory.class)
332                offset += 1;
333            if (paramTypes.length>1 && paramTypes[1]==DisplayContext.class)
334                offset += 1;
335    
336            for (int i=0; i<params.length;i++) {
337                if (String.class.isAssignableFrom(paramTypes[i+offset])) {
338                    // String: leave as is
339                    args[i] = params[i];
340                } else if (Boolean.class.isAssignableFrom(paramTypes[i+offset]) || 
341                           boolean.class.isAssignableFrom(paramTypes[i+offset]) ) {
342                    args[i] = Boolean.valueOf(params[i]);
343                } else if (Object.class.isAssignableFrom(paramTypes[i+offset])) {
344                    // Object: object name
345                    args[i] = NameRepository.get().getObject(params[i]);
346                    logger.debug(params[i]+" -> "+args[i]);
347                    if (args[i]==null) {
348                        logger.warn("Could not find object named "+params[i]);
349                    }
350                }
351            }
352            return createView(label,viewType,args,context);
353        }
354    
355        /**
356         * Creates a view for an object, using the most specific view
357         * constructor available for the type of the object.
358         *
359         * @param label the label of the view to create
360         * @param object the object for which to create a view
361         * @param context the display context
362         */
363        public View createObjectView(String label, Object object,
364                                     DisplayContext context) {
365            if (object==null) {
366                return createView(label,"Object",new Object[] {GuiAC.DEFAULT_VIEW,object}, 
367                                  context);
368            }
369            ClassItem cl = ClassRepository.get().getClass(object);
370            while (cl!=null) {
371                if (hasViewerFor(cl.getName())) {
372                    return createView(label,cl.getName(),
373                                      new Object[] {object}, context);
374                }
375                cl = cl.getSuperclass();
376            }
377            return createView(label,"Object",new Object[] {"default",object}, context);
378        }
379    
380        /**
381         * Creates a view for an object, using the most specific view
382         * constructor available for the type of the object.
383         *
384         * @param label the label of the view to create
385         * @param object the object for which to create a view
386         * @param substance
387         * @param field 
388         * @param context the display context
389         */
390        public View createObjectView(String label, Object object,
391                                     Object substance, FieldItem field,
392                                     DisplayContext context) {
393            if (object==null) {
394                return createView(label,"Object",new Object[] {GuiAC.DEFAULT_VIEW,object}, 
395                                  context);
396            }
397            ClassItem cl = ClassRepository.get().getClass(object);
398            while (cl!=null) {
399                if (hasViewerFor(cl.getName())) {
400                    return createView(label,cl.getName(),
401                                      new Object[] {object,substance,field}, context);
402                }
403                cl = cl.getSuperclass();
404            }
405            return createView(label,"Object",new Object[] {"default",object}, context);
406        }
407    
408        public CompositeView createCompositeView(String label, String viewType, 
409                                                 Object[] params, 
410                                                 DisplayContext context) 
411            throws UnhandledViewTypeException
412        {
413            return (CompositeView)createView(label,viewType,params,context);
414        }
415       
416        public View createView(String label, String viewType, DisplayContext context) 
417            throws UnhandledViewTypeException
418        {
419            return createView(label,viewType,ExtArrays.emptyObjectArray,context);
420        }
421    
422        public CompositeView createCompositeView(String label, String viewType, 
423                                                 DisplayContext context) 
424            throws UnhandledViewTypeException
425        {
426            return (CompositeView)createView(label,viewType,context);
427        }
428    
429        public FieldEditor createEditor(String label, String viewType, 
430                                        Object[] params, 
431                                        DisplayContext context)
432            throws UnhandledViewTypeException
433        {
434            return (FieldEditor)createView(label,viewType,params,context);
435        }
436       
437        /**
438         * Set the constructor for a type of view
439         *
440         * @param viewType the type of the view
441         * @param constructor the constructor to be used to build view of
442         * that type. It should take a ViewFactory as the first parameter
443         */
444        public void setViewConstructor(String viewType, AbstractMethodItem constructor) {
445            constructors.put(viewType,constructor);
446        }
447    
448        public void setViewConstructor(String viewType, String constructor) 
449        {
450            try {
451                setViewConstructor(
452                    viewType,
453                    (AbstractMethodItem)ACConfiguration.convertValue(
454                        constructor,
455                        AbstractMethodItem.class,
456                        imports));
457            } catch (Exception e) {
458                logger.error("setViewConstructor("+viewType+","+constructor+") failed",e);
459            }
460        }
461    
462        /**
463         * Tells wether a view factory is able to build a view for given type.
464         * @param viewType the type of the view
465         * @see #setViewConstructor(String,AbstractMethodItem)
466         */
467        public boolean hasViewerFor(String viewType) {
468            return constructors.containsKey(viewType);
469        }
470    
471        /**
472         * Thrown to indicate that a ViewFactory is unable to build a view
473         * of the given type because no constructor is associated to this
474         * type of view.
475         * @see #setViewConstructor(String,AbstractMethodItem)
476         */
477        public static class UnhandledViewTypeException extends RuntimeException {
478            /**
479             * @param viewType the type of view that the factory is unable to build.
480             */
481            public UnhandledViewTypeException(String viewType) {
482                super("Unable to build a view of type \""+viewType+"\"");
483            }
484        }
485    
486    }