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.text.NumberFormat;
021 import java.util.ArrayList;
022 import java.util.HashMap;
023 import java.util.LinkedHashMap;
024 import java.util.List;
025 import java.util.Map;
026 import java.util.Set;
027
028 import org.apache.camel.dataformat.bindy.util.AnnotationModelLoader;
029 import org.apache.camel.spi.PackageScanClassResolver;
030 import org.apache.camel.util.ObjectHelper;
031 import org.apache.commons.logging.Log;
032 import org.apache.commons.logging.LogFactory;
033
034 /**
035 * The BindyAbstractFactory implements what its common to all the formats
036 * supported by camel bindy
037 */
038 public abstract class BindyAbstractFactory implements BindyFactory {
039 private static final transient Log LOG = LogFactory.getLog(BindyAbstractFactory.class);
040 protected Set<Class<?>> models;
041 protected Map<String, List<Field>> annotedLinkFields = new LinkedHashMap<String, List<Field>>();
042 protected List<Field> linkFields = new ArrayList<Field>();
043 protected String crlf;
044
045 private AnnotationModelLoader modelsLoader;
046 private String[] packageNames;
047
048 public BindyAbstractFactory(PackageScanClassResolver resolver, String... packageNames) throws Exception {
049 this.modelsLoader = new AnnotationModelLoader(resolver);
050 this.packageNames = packageNames;
051
052 if (LOG.isDebugEnabled()) {
053 for (String str : this.packageNames) {
054 LOG.debug("Package name : " + str);
055 }
056 }
057
058 initModel();
059 }
060
061 /**
062 * method uses to initialize the model representing the classes who will
063 * bind the data. This process will scan for classes according to the
064 * package name provided, check the annotated classes and fields.
065 *
066 * @throws Exception
067 */
068 public void initModel() throws Exception {
069 // Find classes defined as Model
070 initModelClasses(this.packageNames);
071 }
072
073 /**
074 * Find all the classes defined as model
075 */
076 private void initModelClasses(String... packageNames) throws Exception {
077 models = modelsLoader.loadModels(packageNames);
078 }
079
080 /**
081 * Find fields annoted in each class of the model
082 */
083 public abstract void initAnnotedFields() throws Exception;
084
085 public abstract void bind(List<String> data, Map<String, Object> model, int line) throws Exception;
086
087 public abstract String unbind(Map<String, Object> model) throws Exception;
088
089 /**
090 * Link objects together
091 */
092 public void link(Map<String, Object> model) throws Exception {
093
094 // Iterate class by class
095 for (String link : annotedLinkFields.keySet()) {
096 List<Field> linkFields = annotedLinkFields.get(link);
097
098 // Iterate through Link fields list
099 for (Field field : linkFields) {
100
101 // Change protection for private field
102 field.setAccessible(true);
103
104 // Retrieve linked object
105 String toClassName = field.getType().getName();
106 Object to = model.get(toClassName);
107
108 ObjectHelper.notNull(to, "No @link annotation has been defined for the oject to link");
109 field.set(model.get(field.getDeclaringClass().getName()), to);
110
111 }
112 }
113 }
114
115 /**
116 * Factory method generating new instances of the model and adding them to a
117 * HashMap
118 *
119 * @return Map is a collection of the objects used to bind data from
120 * records, messages
121 * @throws Exception can be thrown
122 */
123 public Map<String, Object> factory() throws Exception {
124 Map<String, Object> mapModel = new HashMap<String, Object>();
125
126 for (Class<?> cl : models) {
127 Object obj = ObjectHelper.newInstance(cl);
128
129 // Add instance of the class to the Map Model
130 mapModel.put(obj.getClass().getName(), obj);
131 }
132
133 return mapModel;
134 }
135
136 /**
137 * Generate a unique key
138 *
139 * @param key1 The key of the section number
140 * @param key2 The key of the position of the field
141 * @return the key generated
142 */
143 protected static Integer generateKey(Integer key1, Integer key2) {
144 String key2Formated = getNumberFormat().format((long)key2);
145 String keyGenerated = String.valueOf(key1) + key2Formated;
146
147 return Integer.valueOf(keyGenerated);
148 }
149
150 /**
151 * @return NumberFormat
152 */
153 private static NumberFormat getNumberFormat() {
154 // Get instance of NumberFormat
155 NumberFormat nf = NumberFormat.getInstance();
156
157 // set max number of digits to 3 (thousands)
158 nf.setMaximumIntegerDigits(3);
159 nf.setMinimumIntegerDigits(3);
160
161 return nf;
162 }
163
164 /**
165 * Return Default value for primitive type
166 *
167 * @param clazz
168 * @return
169 * @throws Exception
170 */
171 public static Object getDefaultValueforPrimitive(Class<?> clazz) throws Exception {
172
173 if (clazz == byte.class) {
174 return Byte.MIN_VALUE;
175 } else if (clazz == short.class) {
176 return Short.MIN_VALUE;
177 } else if (clazz == int.class) {
178 return Integer.MIN_VALUE;
179 } else if (clazz == long.class) {
180 return Long.MIN_VALUE;
181 } else if (clazz == float.class) {
182 return Float.MIN_VALUE;
183 } else if (clazz == double.class) {
184 return Double.MIN_VALUE;
185 } else if (clazz == char.class) {
186 return Character.MIN_VALUE;
187 } else if (clazz == boolean.class) {
188 return false;
189 } else {
190 return null;
191 }
192
193 }
194
195 /**
196 * Find the carriage return set
197 */
198 public String getCarriageReturn() {
199 return crlf;
200 }
201 }