001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.xbean.spring.context.impl;
018    
019    import java.lang.reflect.Constructor;
020    import java.lang.reflect.Method;
021    import java.util.ArrayList;
022    import java.util.Collections;
023    import java.util.Properties;
024    import java.util.StringTokenizer;
025    
026    /**
027     * A helper class which understands how to map an XML namespaced element to
028     * Spring bean configurations
029     *
030     * @author James Strachan
031     * @version $Id$
032     * @since 2.0
033     */
034    public class MappingMetaData {
035        private Properties properties;
036        private String packageName;
037    
038        /**
039         * Creates an empty MappingMetaData for the specified Java package.
040         * @param packageName the Java package to map
041         */
042        public MappingMetaData(String packageName) {
043            this.packageName = packageName;
044            this.properties = new Properties();
045        }
046    
047        /**
048         * Creates MappingMetaData using the specified properties which contan the package name.
049         * @param properties
050         */
051        public MappingMetaData(Properties properties) {
052            this.properties = properties;
053        }
054    
055        /**
056         * Returns the Java class name for the given XML element name
057         */
058        public String getClassName(String localName) {
059            String className = properties.getProperty(localName);
060            if (className == null && packageName != null) {
061                if (packageName.length() > 0) {
062                    className = packageName + "." + localName;
063                }
064                else {
065                    className = localName;
066                }
067            }
068            return className;
069        }
070    
071        /**
072         * Returns the property name for the given element and attribute name
073         * 
074         * @param elementName the XML local name of the element
075         * @param attributeName the XML local name of the attribute
076         * @return the property name to use or null if the attribute is not a valid property
077         */
078        public String getPropertyName(String elementName, String attributeName) {
079            return properties.getProperty(elementName + ".alias." + attributeName, attributeName);
080        }
081    
082        /**
083         * Returns a valid property name if the childElementName maps to a nested list property
084         * 
085         * @param elementName the owner element
086         * @param childElementName is the child element name which maps to the nested list property 
087         * @return the property name if available or null if it is not applicable
088         */
089        public String getNestedListProperty(String elementName, String childElementName) {
090            return properties.getProperty(elementName + ".list." + childElementName);
091        }
092        
093        /**
094         * Returns a valid property name if the childElementName maps to a nested bean property
095         * 
096         * @param elementName the owner element
097         * @param childElementName is the child element name which maps to the nested bean property 
098         * @return the property name if available or null if it is not applicable
099         */
100        public String getNestedProperty(String elementName, String childElementName) {
101            return properties.getProperty(elementName + ".alias." + childElementName);
102        }
103    
104        public boolean isDefaultConstructor(Constructor constructor) {
105            String property = properties.getProperty(constructorToPropertyName(constructor) + ".default");
106            if (property != null) {
107                return Boolean.valueOf(property).booleanValue();
108            }
109            return false;
110        }
111    
112        public boolean isDefaultFactoryMethod(Class beanClass, Method factoryMethod) {
113            String property = properties.getProperty(methodToPropertyName(beanClass, factoryMethod) + ".default");
114            if (property != null) {
115                return Boolean.valueOf(property).booleanValue();
116            }
117            return false;
118        }
119    
120        public String[] getParameterNames(Constructor constructor) {
121            String property = properties.getProperty(constructorToPropertyName(constructor) + ".parameterNames");
122            if (property != null) {
123                ArrayList names = Collections.list(new StringTokenizer(property, ", "));
124                return (String[]) names.toArray(new String[0]);
125            }
126            return null;
127        }
128    
129        public String[] getParameterNames(Class beanClass, Method factoryMethod) {
130            String property = properties.getProperty(methodToPropertyName(beanClass, factoryMethod) + ".parameterNames");
131            if (property != null) {
132                ArrayList names = Collections.list(new StringTokenizer(property, ", "));
133                return (String[]) names.toArray(new String[0]);
134            }
135            return null;
136        }
137    
138        public static String constructorToPropertyName(Constructor constructor) {
139            StringBuffer buf = new StringBuffer();
140            buf.append(constructor.getName()).append("(");
141            Class[] parameterTypes = constructor.getParameterTypes();
142            for (int i = 0; i < parameterTypes.length; i++) {
143                Class parameterType = parameterTypes[i];
144                buf.append(parameterType.getName());
145                if (i < parameterTypes.length - 1) {
146                    buf.append(",");
147                }
148            }
149            buf.append(")");
150            return buf.toString();
151        }
152    
153        public static String methodToPropertyName(Class beanClass, Method method) {
154            StringBuffer buf = new StringBuffer();
155            buf.append(beanClass.getName()).append(".");
156            buf.append(method.getName()).append("(");
157            Class[] parameterTypes = method.getParameterTypes();
158            for (int i = 0; i < parameterTypes.length; i++) {
159                Class parameterType = parameterTypes[i];
160                buf.append(parameterType.getName());
161                if (i < parameterTypes.length - 1) {
162                    buf.append(",");
163                }
164            }
165            buf.append(")");
166            return buf.toString();
167        }
168    
169        public String getInitMethodName(String elementName) {
170            return properties.getProperty(elementName + ".initMethod");
171        }
172    
173        public String getDestroyMethodName(String elementName) {
174            return properties.getProperty(elementName + ".destroyMethod");
175        }
176    
177        public String getFactoryMethodName(String elementName) {
178            return properties.getProperty(elementName + ".factoryMethod");
179        }
180    
181        public String getContentProperty(String elementName) {
182            return properties.getProperty(elementName + ".contentProperty");
183        }
184        
185        public String getMapEntryName(String elementName, String property) {
186            return properties.getProperty(elementName + "." + property + ".map.entryName");
187        }
188    
189        public String getMapKeyName(String elementName, String property) {
190            return properties.getProperty(elementName + "." + property + ".map.keyName");
191        }
192    
193        public boolean isFlatMap(String elementName, String property) {
194            return properties.getProperty(elementName + "." + property + ".map.flat") != null;
195        }
196        
197        public String getMapDupsMode(String elementName, String property) {
198            return properties.getProperty(elementName + "." + property + ".map.dups");
199        }
200        
201        public String getMapDefaultKey(String elementName, String property) {
202            return properties.getProperty(elementName + "." + property + ".map.defaultKey");
203        }
204        
205        public String getFlatCollectionProperty(String elementName, String property)
206        {
207            return properties.getProperty(elementName + "." + property + ".flatCollection");
208        }
209        
210        public boolean isFlatProperty(String elementName, String property)  {
211            return properties.getProperty(elementName + "." + property + ".flat") != null;
212        }
213        
214        public String getPropertyEditor(String elementName, String property)
215        {
216            return properties.getProperty(elementName + "." + property + ".propertyEditor");
217        }
218    
219    }