View Javadoc

1   /*
2    * Copyright 2000-2005 The Apache Software Foundation.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
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(); // contains the class descriptor which have not ancestors 
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                               //cd.setSuperClassDescriptor(interfaceClassDescriptor);
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 }