1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.portals.graffito.jcr.mapper.impl;
17
18
19
20 import java.io.InputStream;
21 import java.util.ArrayList;
22 import java.util.Collection;
23 import java.util.Iterator;
24 import java.util.List;
25 import java.util.Map;
26 import org.apache.commons.logging.Log;
27 import org.apache.commons.logging.LogFactory;
28 import org.apache.portals.graffito.jcr.exception.InitMapperException;
29 import org.apache.portals.graffito.jcr.exception.JcrMappingException;
30 import org.apache.portals.graffito.jcr.mapper.Mapper;
31 import org.apache.portals.graffito.jcr.mapper.model.ClassDescriptor;
32 import org.apache.portals.graffito.jcr.mapper.model.MappingDescriptor;
33
34 /***
35 *
36 * Digester implementation for {@link org.apache.portals.graffito.jcr.mapper.Mapper}
37 *
38 * @author <a href="mailto:christophe.lombart@sword-technologies.com">Lombart Christophe </a>
39 * @author <a href='mailto:the_mindstorm[at]evolva[dot]ro'>Alexandru Popescu</a>
40 */
41 public class DigesterMapperImpl implements Mapper {
42 private static final Log log = LogFactory.getLog(DigesterMapperImpl.class);
43
44 private MappingDescriptor mappingDescriptor;
45 private Collection rootClassDescriptors = new ArrayList();
46
47 private String[] mappingFiles;
48 private InputStream[] mappingStreams;
49 private DigesterDescriptorReader descriptorReader;
50
51 /***
52 * No-arg constructor.
53 */
54 public DigesterMapperImpl() {
55 }
56
57 /***
58 * Constructor
59 *
60 * @param xmlFile The xml mapping file to read
61 *
62 */
63 public DigesterMapperImpl(String xmlFile) {
64 this.mappingFiles = new String[] { xmlFile };
65 this.buildMapper();
66 }
67
68 /***
69 * Constructor
70 *
71 * @param files a set of xml mapping files to read
72 *
73 */
74 public DigesterMapperImpl(String[] files) {
75 this.mappingFiles = files;
76 this.buildMapper();
77 }
78
79 /***
80 * Constructor
81 *
82 * @param stream The xml mapping file to read
83 */
84 public DigesterMapperImpl(InputStream stream) {
85 this.mappingStreams = new InputStream[] { stream };
86 this.buildMapper();
87 }
88
89 /***
90 * Constructor
91 *
92 * @param streams a set of mapping files to read
93 *
94 */
95 public DigesterMapperImpl(InputStream[] streams) {
96 this.mappingStreams = streams;
97 this.buildMapper();
98 }
99
100 /***
101 * Set a mapping file.
102 *
103 * @param file path to mapping file
104 */
105 public void setMappingFile(String file) {
106 setMappingFiles(new String[] { file });
107 this.buildMapper();
108 }
109
110 /***
111 *
112 * @param files
113 */
114 public void setMappingFiles(String[] files) {
115 this.mappingFiles = files;
116 }
117
118 public void setMappingStream(InputStream stream) {
119 setMappingStreams(new InputStream[] { stream });
120 }
121
122 public void setMappingStreams(InputStream[] streams) {
123 this.mappingStreams = streams;
124 }
125
126 public void setDescriptorReader(DigesterDescriptorReader reader) {
127 this.descriptorReader = reader;
128 }
129
130 private Mapper buildMapper() {
131 if (this.descriptorReader == null) {
132 this.descriptorReader = new DigesterDescriptorReader();
133 }
134 if (this.mappingFiles != null && this.mappingFiles.length > 0) {
135 log.info("Read the xml mapping file : " + this.mappingFiles[0]);
136 this.mappingDescriptor = this.descriptorReader.loadClassDescriptors(this.mappingFiles[0]);
137 this.mappingDescriptor.setMapper(this);
138
139 for (int i = 1; i < this.mappingFiles.length; i++) {
140 log.info("Read the xml mapping file : " + this.mappingFiles[i]);
141 MappingDescriptor anotherMappingDescriptor = this.descriptorReader.loadClassDescriptors(this.mappingFiles[i]);
142 this.mappingDescriptor.getClassDescriptorsByClassName().putAll(anotherMappingDescriptor.getClassDescriptorsByClassName());
143 this.mappingDescriptor.getClassDescriptorsByNodeType().putAll(anotherMappingDescriptor.getClassDescriptorsByNodeType());
144
145 }
146 }
147 else if (this.mappingStreams != null && this.mappingStreams.length > 0) {
148 log.info("Read the stream mapping file : " + this.mappingStreams[0].toString());
149 this.mappingDescriptor = this.descriptorReader.loadClassDescriptors(this.mappingStreams[0]);
150 this.mappingDescriptor.setMapper(this);
151
152 for (int i = 1; i < this.mappingStreams.length; i++) {
153 log.info("Read the stream mapping file : " + this.mappingStreams[i].toString());
154 MappingDescriptor anotherMappingDescriptor = this.descriptorReader.loadClassDescriptors(this.mappingStreams[i]);
155 this.mappingDescriptor.getClassDescriptorsByClassName().putAll(anotherMappingDescriptor.getClassDescriptorsByClassName());
156 this.mappingDescriptor.getClassDescriptorsByNodeType().putAll(anotherMappingDescriptor.getClassDescriptorsByNodeType());
157 }
158 }
159 if (null != this.mappingDescriptor) {
160 List errors = new ArrayList();
161 errors = solveReferences(errors);
162 errors = validateDescriptors(errors, rootClassDescriptors);
163
164 if (!errors.isEmpty()) {
165 throw new InitMapperException("Mapping files contain errors."
166 + getErrorMessage(errors));
167 }
168 }
169 else {
170 throw new InitMapperException("No mappings were provided");
171 }
172
173 return this;
174 }
175
176 private List solveReferences(List errors) {
177 for(Iterator it = this.mappingDescriptor.getClassDescriptorsByClassName().entrySet().iterator(); it.hasNext(); ) {
178 Map.Entry entry = (Map.Entry) it.next();
179 ClassDescriptor cd = (ClassDescriptor) entry.getValue();
180
181 if (null != cd.getExtend() && !"".equals(cd.getExtend()))
182 {
183 ClassDescriptor superClassDescriptor = this.mappingDescriptor.getClassDescriptorByName(cd.getExtend());
184
185 if (null == superClassDescriptor)
186 {
187 errors.add("Cannot find mapping for class "
188 + cd.getExtend()
189 + " referenced as extends from "
190 + cd.getClassName());
191 }
192 else
193 {
194 log.debug("Class " +cd.getClassName() + " extends " + cd.getExtend());
195 cd.setSuperClassDescriptor(superClassDescriptor);
196 }
197 }
198 else
199 {
200 rootClassDescriptors.add(cd);
201 }
202
203 Collection interfaces = cd.getImplements();
204 if (interfaces.size() > 0)
205 {
206 for (Iterator iterator = interfaces.iterator(); iterator.hasNext();)
207 {
208 String interfaceName= (String) iterator.next();
209 ClassDescriptor interfaceClassDescriptor = this.mappingDescriptor.getClassDescriptorByName(interfaceName);
210
211 if (null == interfaceClassDescriptor)
212 {
213 errors.add("Cannot find mapping for interface "
214 + interfaceName
215 + " referenced as implements from "
216 + cd.getClassName());
217 }
218 else
219 {
220 log.debug("Class " +cd.getClassName() + " implements " + interfaceName);
221
222 interfaceClassDescriptor.addDescendantClassDescriptor(cd);
223 }
224
225 }
226 }
227
228 }
229
230 return errors;
231 }
232
233 /***
234 * Validate all class descriptors.
235 * This method validates the toplevel ancestors and after the descendants.
236 * Otherwise, we can have invalid settings in the class descriptors
237 * @param errors all errors found during the validation process
238 * @param classDescriptors the ancestor classdescriptors
239 * @return
240 */
241 private List validateDescriptors(List errors, Collection classDescriptors ) {
242 for(Iterator it = classDescriptors.iterator(); it.hasNext(); ) {
243 ClassDescriptor classDescriptor = (ClassDescriptor) it.next();
244 try {
245 classDescriptor.afterPropertiesSet();
246 if (classDescriptor.hasDescendants()) {
247 errors = validateDescriptors(errors, classDescriptor.getDescendantClassDescriptors());
248 }
249 }
250 catch(JcrMappingException jme) {
251 log.warn("Mapping of class " + classDescriptor.getClassName() + " is invalid", jme);
252 errors.add(jme.getMessage());
253 }
254 }
255 return errors;
256 }
257
258 private String getErrorMessage(List errors) {
259 final String lineSep = System.getProperty("line.separator");
260 StringBuffer buf = new StringBuffer();
261 for(Iterator it = errors.iterator(); it.hasNext();) {
262 buf.append(lineSep).append(it.next());
263 }
264
265 return buf.toString();
266 }
267
268 /***
269 *
270 * @see org.apache.portals.graffito.jcr.mapper.Mapper#getClassDescriptorByClass(java.lang.Class)
271 */
272 public ClassDescriptor getClassDescriptorByClass(Class clazz) {
273 return mappingDescriptor.getClassDescriptorByName(clazz.getName());
274 }
275
276 /***
277 * @see org.apache.portals.graffito.jcr.mapper.Mapper#getClassDescriptorByNodeType(String)
278 */
279 public ClassDescriptor getClassDescriptorByNodeType(String jcrNodeType) {
280 return mappingDescriptor.getClassDescriptorByNodeType(jcrNodeType);
281 }
282
283 }