001/** 002 * Copyright 2005-2015 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.kuali.rice.devtools.jpa.eclipselink.conv.ojb; 017 018import org.apache.logging.log4j.Logger; 019import org.apache.logging.log4j.LogManager; 020import org.apache.ojb.broker.metadata.ClassDescriptor; 021import org.apache.ojb.broker.metadata.CollectionDescriptor; 022import org.apache.ojb.broker.metadata.ConnectionDescriptorXmlHandler; 023import org.apache.ojb.broker.metadata.ConnectionRepository; 024import org.apache.ojb.broker.metadata.DescriptorRepository; 025import org.apache.ojb.broker.metadata.FieldDescriptor; 026import org.apache.ojb.broker.metadata.MetadataException; 027import org.apache.ojb.broker.metadata.ObjectReferenceDescriptor; 028import org.apache.ojb.broker.metadata.RepositoryXmlHandler; 029import org.apache.ojb.broker.util.ClassHelper; 030import org.xml.sax.InputSource; 031import org.xml.sax.SAXException; 032import org.xml.sax.XMLReader; 033 034import javax.xml.parsers.ParserConfigurationException; 035import javax.xml.parsers.SAXParser; 036import javax.xml.parsers.SAXParserFactory; 037import java.io.File; 038import java.io.IOException; 039import java.io.InputStream; 040import java.net.MalformedURLException; 041import java.net.URL; 042import java.net.URLConnection; 043import java.util.ArrayList; 044import java.util.Collection; 045import java.util.HashSet; 046import java.util.Map; 047import java.util.Set; 048 049public final class OjbUtil { 050 051 private static final Logger LOG = LogManager.getLogger(OjbUtil.class); 052 053 private OjbUtil() { 054 throw new UnsupportedOperationException("do not call"); 055 } 056 057 /** 058 * Starting with a root class, get the entire tree of mapped objects including collections and references. 059 * Cycles are correctly handled. 060 * 061 * @param rootClass the top level class to start with. 062 * @return a collection of classes to process 063 */ 064 public static Collection<String> getMappedTree(String rootClass, Collection<DescriptorRepository> descriptorRepositories) { 065 final Set<String> processed = new HashSet<String>(); 066 getMappedTree(rootClass, descriptorRepositories, processed); 067 return processed; 068 } 069 070 private static void getMappedTree(String rootClass, Collection<DescriptorRepository> descriptorRepositories, Set<String> processed) { 071 if (processed.contains(rootClass)) { 072 return; 073 } 074 075 processed.add(rootClass); 076 final ClassDescriptor cd = findClassDescriptor(rootClass, descriptorRepositories); 077 if (cd != null) { 078 final Collection<ObjectReferenceDescriptor> ords = cd.getObjectReferenceDescriptors(); 079 if (ords != null) { 080 for (ObjectReferenceDescriptor ord : ords) { 081 getMappedTree(ord.getItemClassName(), descriptorRepositories, processed); 082 } 083 } 084 085 final Collection<CollectionDescriptor> clds = cd.getCollectionDescriptors(); 086 if (clds != null) { 087 for (ObjectReferenceDescriptor cld : clds) { 088 getMappedTree(cld.getItemClassName(), descriptorRepositories, processed); 089 } 090 } 091 092 } else { 093 LOG.warn("ClassDescriptor not found for " + rootClass); 094 } 095 } 096 097 public static boolean isMappedColumn(String clazz, String fieldName, Collection<DescriptorRepository> descriptorRepositories) { 098 final ClassDescriptor cd = findClassDescriptor(clazz, descriptorRepositories); 099 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}