001    package org.tynamo.services;
002    
003    import ognl.Ognl;
004    import ognl.OgnlException;
005    import org.apache.tapestry5.beaneditor.DataType;
006    import org.apache.tapestry5.ioc.services.PropertyAdapter;
007    import org.apache.tapestry5.services.DataTypeAnalyzer;
008    import org.slf4j.Logger;
009    import org.tynamo.descriptor.TynamoClassDescriptor;
010    import org.tynamo.descriptor.TynamoPropertyDescriptor;
011    import org.tynamo.util.Pair;
012    
013    import java.util.List;
014    
015    public class TynamoDataTypeAnalyzer implements DataTypeAnalyzer
016    {
017    
018            private final DescriptorService descriptorService;
019            private final List<Pair> editorMap;
020            private final Logger logger;
021    
022            /**
023             * @param descriptorService
024             * @param editorMap              A map where the keys are OGNL expressions and the values are data type identifier used to select editor (or display) blocks
025             */
026            public TynamoDataTypeAnalyzer(final DescriptorService descriptorService, final List<Pair> editorMap, final Logger logger)
027            {
028                    this.descriptorService = descriptorService;
029                    this.editorMap = editorMap;
030                    this.logger = logger;
031            }
032    
033            /**
034             * The first data type identifier in the editorMap whose "key" evaluates to true for the descriptor will be used
035             * to load an editor (or display) block for the descriptor. Returns null if no match is found.
036             *
037             * @return returns the data type identifier, if known, or returns null if not known.
038             */
039            public String identifyDataType(PropertyAdapter adapter)
040            {
041                    if (adapter.getAnnotation(DataType.class) == null)
042                    {
043                            TynamoPropertyDescriptor propertyDescriptor = getPropertyDescriptor(adapter);
044                            if (propertyDescriptor != null) //ignore excluded properties
045                            {
046                                    for (Pair<String, String> entry : editorMap)
047                                    {
048                                            try
049                                            {
050                                                    if ((Boolean) Ognl.getValue(entry.getKey(), propertyDescriptor))
051                                                    {
052                                                            return entry.getValue();
053                                                    }
054                                            } catch (OgnlException oe)
055                                            {
056                                                    logger.error(String.format("Error evaluating expression: \"%s\" for the \"%s\" property of %s",
057                                                                    entry.getKey(), adapter.getName(), adapter.getBeanType().getName()), oe);
058                                            }
059                                    }
060                            }
061                    }
062    
063                    // To avoid "no strategy" exceptions, we expect a contribution of Object.class to the empty
064                    // string. We convert that back to a null.
065                    return null;
066            }
067    
068            private TynamoPropertyDescriptor getPropertyDescriptor(PropertyAdapter adapter)
069            {
070    
071                    TynamoClassDescriptor classDescriptor = descriptorService.getClassDescriptor(adapter.getBeanType());
072                    TynamoPropertyDescriptor propertyDescriptor = null;
073    
074                    if (classDescriptor != null)
075                    {
076                            propertyDescriptor = classDescriptor.getPropertyDescriptor(adapter.getName());
077                    }
078    
079                    return propertyDescriptor;
080            }
081    
082    }
083