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.camel.dataformat.bindy;
018    
019    import java.lang.reflect.Field;
020    import java.util.HashMap;
021    import java.util.LinkedHashMap;
022    import java.util.List;
023    import java.util.Map;
024    import java.util.Set;
025    
026    import org.apache.camel.dataformat.bindy.util.AnnotationModelLoader;
027    import org.apache.camel.spi.PackageScanClassResolver;
028    import org.apache.camel.util.ObjectHelper;
029    import org.apache.commons.logging.Log;
030    import org.apache.commons.logging.LogFactory;
031    
032    /**
033     * The BindyAbstractFactory implements what its common to all the 
034     * formats supported by camel bindy
035     */
036    public abstract class BindyAbstractFactory implements BindyFactory {
037        private static final transient Log LOG = LogFactory.getLog(BindyAbstractFactory.class);
038        protected Set<Class> models;
039        protected Map<String, Field> mapAnnotedLinkField = new LinkedHashMap<String, Field>();    
040        protected String crlf;
041        
042        private AnnotationModelLoader modelsLoader;
043        
044        private String packageName;
045    
046        public BindyAbstractFactory(PackageScanClassResolver resolver, String packageName) throws Exception {
047            this.modelsLoader = new AnnotationModelLoader(resolver);
048            this.packageName = packageName;
049            initModel();
050        }
051    
052        /**
053         * method uses to initialize the model representing the classes who will
054         * bind the data. This process will scan for classes according to the package
055         * name provided, check the classes and fields annoted.
056         * 
057         * @throws Exception
058         */
059        public void initModel() throws Exception {
060    
061            // Find classes defined as Model
062            initModelClasses(packageName);
063    
064        }
065    
066        /**
067         * Find all the classes defined as model
068         */
069        private void initModelClasses(String packageName) throws Exception {
070            models = modelsLoader.loadModels(packageName);
071        }
072    
073        /**
074         * Find fields annoted in each class of the model
075         */
076        public abstract void initAnnotedFields() throws Exception;
077    
078        public abstract void bind(List<String> data, Map<String, Object> model) throws Exception;
079    
080        public abstract String unbind(Map<String, Object> model) throws Exception;
081    
082        /**
083         * Link objects together (Only 1to1 relation is allowed)
084         */
085        public void link(Map<String, Object> model) throws Exception {
086    
087            for (String link : mapAnnotedLinkField.keySet()) {
088    
089                Field field = mapAnnotedLinkField.get(link);
090                field.setAccessible(true);
091    
092                // Retrieve linked object
093                String toClassName = field.getType().getName();
094                Object to = model.get(toClassName);
095    
096                ObjectHelper.notNull(to, "No @link annotation has been defined for the oject to link");
097                field.set(model.get(field.getDeclaringClass().getName()), to);
098    
099            }
100        }
101    
102        /**
103         * Factory method generating new instances of the model and adding them to a
104         * HashMap
105         * 
106         * @return Map is a collection of the objects used to bind data from records, messages
107         * @throws Exception can be thrown
108         */
109        public Map<String, Object> factory() throws Exception {
110    
111            Map<String, Object> mapModel = new HashMap<String, Object>();
112    
113            for (Class<?> cl : models) {
114    
115                Object obj = ObjectHelper.newInstance(cl);
116    
117                // Add instance of the class to the Map Model
118                mapModel.put(obj.getClass().getName(), obj);
119    
120            }
121    
122            return mapModel;
123        }
124        
125        /**
126         * Find the carriage return set
127         */
128        public String getCarriageReturn() {
129            return crlf;
130        }
131    }