View Javadoc
1   /**
2    * Copyright 2005-2014 The Kuali Foundation
3    *
4    * Licensed under the Educational Community 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.opensource.org/licenses/ecl2.php
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.kuali.rice.devtools.jpa.eclipselink.conv.ojb;
17  
18  import org.apache.commons.logging.Log;
19  import org.apache.commons.logging.LogFactory;
20  import org.apache.ojb.broker.metadata.ClassDescriptor;
21  import org.apache.ojb.broker.metadata.CollectionDescriptor;
22  import org.apache.ojb.broker.metadata.ConnectionDescriptorXmlHandler;
23  import org.apache.ojb.broker.metadata.ConnectionRepository;
24  import org.apache.ojb.broker.metadata.DescriptorRepository;
25  import org.apache.ojb.broker.metadata.FieldDescriptor;
26  import org.apache.ojb.broker.metadata.MetadataException;
27  import org.apache.ojb.broker.metadata.ObjectReferenceDescriptor;
28  import org.apache.ojb.broker.metadata.RepositoryXmlHandler;
29  import org.apache.ojb.broker.util.ClassHelper;
30  import org.xml.sax.InputSource;
31  import org.xml.sax.SAXException;
32  import org.xml.sax.XMLReader;
33  
34  import javax.xml.parsers.ParserConfigurationException;
35  import javax.xml.parsers.SAXParser;
36  import javax.xml.parsers.SAXParserFactory;
37  import java.io.File;
38  import java.io.IOException;
39  import java.io.InputStream;
40  import java.net.MalformedURLException;
41  import java.net.URL;
42  import java.net.URLConnection;
43  import java.util.ArrayList;
44  import java.util.Collection;
45  import java.util.HashSet;
46  import java.util.Map;
47  import java.util.Set;
48  
49  public final class OjbUtil {
50  
51      private static final Log LOG = LogFactory.getLog(OjbUtil.class);
52  
53      private OjbUtil() {
54          throw new UnsupportedOperationException("do not call");
55      }
56  
57      /**
58       * Starting with a root class, get the entire tree of mapped objects including collections and references.
59       * Cycles are correctly handled.
60       *
61       * @param rootClass the top level class to start with.
62       * @return a collection of classes to process
63       */
64      public static Collection<String> getMappedTree(String rootClass, Collection<DescriptorRepository> descriptorRepositories) {
65          final Set<String> processed = new HashSet<String>();
66          getMappedTree(rootClass, descriptorRepositories, processed);
67          return processed;
68      }
69  
70      private static void getMappedTree(String rootClass, Collection<DescriptorRepository> descriptorRepositories, Set<String> processed) {
71          if (processed.contains(rootClass)) {
72              return;
73          }
74  
75          processed.add(rootClass);
76          final ClassDescriptor cd = findClassDescriptor(rootClass, descriptorRepositories);
77          if (cd != null) {
78              final Collection<ObjectReferenceDescriptor> ords = cd.getObjectReferenceDescriptors();
79              if (ords != null) {
80                  for (ObjectReferenceDescriptor ord : ords) {
81                      getMappedTree(ord.getItemClassName(), descriptorRepositories, processed);
82                  }
83              }
84  
85              final Collection<CollectionDescriptor> clds = cd.getCollectionDescriptors();
86              if (clds != null) {
87                  for (ObjectReferenceDescriptor cld : clds) {
88                      getMappedTree(cld.getItemClassName(), descriptorRepositories, processed);
89                  }
90              }
91  
92          } else {
93              LOG.warn("ClassDescriptor not found for " + rootClass);
94          }
95      }
96  
97      public static boolean isMappedColumn(String clazz, String fieldName, Collection<DescriptorRepository> descriptorRepositories) {
98          final ClassDescriptor cd = findClassDescriptor(clazz, descriptorRepositories);
99          if (cd != null) {
100             return cd.getFieldDescriptorByName(fieldName) != null ||
101                     cd.getObjectReferenceDescriptorByName(fieldName) != null ||
102                     cd.getCollectionDescriptorByName(fieldName) != null;
103         }
104         return false;
105     }
106 
107     public static Collection<DescriptorRepository> getDescriptorRepositories(Collection<String> ojbFiles) throws Exception {
108         final Collection<DescriptorRepository> drs = new ArrayList<DescriptorRepository>();
109 
110         //first parse & get all of the mapped classes
111         for (String file : ojbFiles) {
112             DescriptorRepository repository = OjbUtil.readDescriptorRepository(file);
113             if ( repository != null ) {
114                 drs.add(repository);
115             }
116         }
117 
118         return drs;
119     }
120 
121     public static ClassDescriptor findClassDescriptor(String clazz, Collection<DescriptorRepository> descriptorRepositories) {
122         for (DescriptorRepository dr : descriptorRepositories) {
123             ClassDescriptor cd = (ClassDescriptor) dr.getDescriptorTable().get(clazz);
124 
125             if (cd != null) {
126                 //handle extends.  don't return class descriptor for extent classes
127                 if (cd.getExtentClassNames() == null || cd.getExtentClassNames().isEmpty()) {
128                     return cd;
129                 }
130             }
131         }
132         return null;
133     }
134 
135     public static FieldDescriptor findFieldDescriptor(String clazz, String fieldName, Collection<DescriptorRepository> descriptorRepositories) {
136         final ClassDescriptor cd = findClassDescriptor(clazz, descriptorRepositories);
137         return cd != null ? cd.getFieldDescriptorByName(fieldName) : null;
138     }
139 
140     public static ObjectReferenceDescriptor findObjectReferenceDescriptor(String clazz, String fieldName, Collection<DescriptorRepository> descriptorRepositories) {
141         final ClassDescriptor cd = findClassDescriptor(clazz, descriptorRepositories);
142         return cd != null ? cd.getObjectReferenceDescriptorByName(fieldName) : null;
143     }
144 
145     public static CollectionDescriptor findCollectionDescriptor(String clazz, String fieldName, Collection<DescriptorRepository> descriptorRepositories) {
146         final ClassDescriptor cd = findClassDescriptor(clazz, descriptorRepositories);
147         return cd != null ? cd.getCollectionDescriptorByName(fieldName) : null;
148     }
149 
150     public static Collection<String> getPrimaryKeyNames(String clazz, Collection<DescriptorRepository> descriptorRepositories) {
151         final Collection<String> pks = new ArrayList<String>();
152         final ClassDescriptor cd = OjbUtil.findClassDescriptor(clazz, descriptorRepositories);
153         for(FieldDescriptor pk : cd.getPkFields()) {
154             pks.add(pk.getAttributeName());
155         }
156         return pks;
157     }
158 
159     /**
160      * Parses a repository file and populates an ojb datastructure representing the file.
161      * @param filename the file to parse
162      * @return a DescriptorRepository or null
163      */
164     public static DescriptorRepository readDescriptorRepository(String filename) {
165         LOG.info( "Processing Repository: " + filename);
166         try {
167             return (DescriptorRepository) buildRepository(filename, DescriptorRepository.class);
168         } catch (Exception e) {
169             LOG.error("Unable to process descriptor repository: " + filename);
170             LOG.error( e.getMessage() );
171             // Explicitly not logging the exception - it has already been dumped by earlier logging 
172         }
173         return null;
174     }
175 
176     /**
177      * Gets all the mapped classes
178      */
179     public static Set<String> mappedClasses(Collection<DescriptorRepository> descriptors) throws Exception {
180         final Set<String> mappedClasses = new HashSet<String>();
181         for (DescriptorRepository dr : descriptors) {
182             for (Map.Entry<String, ClassDescriptor> entry : ((Map<String, ClassDescriptor>) dr.getDescriptorTable()).entrySet()) {
183                 final Collection<String> extents = entry.getValue().getExtentClassNames();
184                 if (extents != null && !extents.isEmpty()) {
185                     mappedClasses.addAll(extents);
186                 } else {
187                     mappedClasses.add(entry.getKey());
188                 }
189             }
190         }
191         return mappedClasses;
192     }
193 
194 
195     /**
196      * Gets all the super classes & stopping when the super class matches a package prefix
197      */
198     public static Set<String> getSuperClasses(String clazzName, String packagePrefixToStop) throws Exception {
199 
200         final Set<String> superClasses = new HashSet<String>();
201 
202         Class<?> clazz = Class.forName(clazzName);
203         for (Class<?> sc = clazz.getSuperclass(); sc != null && sc != Object.class && !sc.getName().startsWith(packagePrefixToStop);) {
204             superClasses.add(sc.getName());
205             sc = sc.getSuperclass();
206         }
207 
208         return superClasses;
209     }
210 
211     private static Object buildRepository(String repositoryFileName, Class targetRepository) throws IOException, ParserConfigurationException, SAXException {
212         URL url = buildURL(repositoryFileName);
213 
214         String pathName = url.toExternalForm();
215 
216         LOG.debug("Building repository from :" + pathName);
217         InputSource source = new InputSource(pathName);
218         URLConnection conn = url.openConnection();
219         conn.setUseCaches(false);
220         conn.connect();
221         InputStream i = conn.getInputStream();
222         source.setByteStream(i);
223         try {
224             return readMetadataFromXML(source, targetRepository);
225         } finally {
226             try {
227                 i.close();
228             } catch (IOException x) {
229                 LOG.warn("unable to close repository input stream [" + x.getMessage() + "]", x);
230             }
231         }
232     }
233 
234 
235     private static Object readMetadataFromXML(InputSource source, Class target) throws ParserConfigurationException, SAXException, IOException {
236         // get a xml reader instance:
237         SAXParserFactory factory = SAXParserFactory.newInstance();
238         LOG.debug("RepositoryPersistor using SAXParserFactory : " + factory.getClass().getName());
239 
240         SAXParser p = factory.newSAXParser();
241         XMLReader reader = p.getXMLReader();
242 
243         Object result;
244         if (DescriptorRepository.class.equals(target)) {
245             // create an empty repository:
246             DescriptorRepository repository = new DescriptorRepository();
247             // create handler for building the repository structure
248             org.xml.sax.ContentHandler handler = new RepositoryXmlHandler(repository);
249             // tell parser to use our handler:
250             reader.setContentHandler(handler);
251             reader.parse(source);
252             result = repository;
253         } else if (ConnectionRepository.class.equals(target)) {
254             // create an empty repository:
255             ConnectionRepository repository = new ConnectionRepository();
256             // create handler for building the repository structure
257             org.xml.sax.ContentHandler handler = new ConnectionDescriptorXmlHandler(repository);
258             // tell parser to use our handler:
259             reader.setContentHandler(handler);
260             reader.parse(source);
261             //LoggerFactory.getBootLogger().info("loading XML took " + (stop - start) + " msecs");
262             result = repository;
263         } else
264             throw new MetadataException("Could not build a repository instance for '" + target +
265                     "', using source " + source);
266         return result;
267     }
268 
269     private static URL buildURL(String repositoryFileName) throws MalformedURLException {
270         //j2ee compliant lookup of resources
271         URL url = ClassHelper.getResource(repositoryFileName);
272 
273         // don't be too strict: if resource is not on the classpath, try ordinary file lookup
274         if (url == null) {
275             try {
276                 url = new File(repositoryFileName).toURL();
277             }
278             catch (MalformedURLException ignore) {
279             }
280         }
281 
282         if (url != null) {
283             LOG.info("OJB Descriptor Repository: " + url);
284         } else {
285             throw new MalformedURLException("did not find resource " + repositoryFileName);
286         }
287         return url;
288     }
289 }