001package org.biopax.paxtools.model; 002 003 004import org.apache.commons.logging.Log; 005import org.apache.commons.logging.LogFactory; 006import org.biopax.paxtools.impl.BioPAXElementImpl; 007import org.biopax.paxtools.impl.ModelImpl; 008 009import java.lang.reflect.Constructor; 010import java.lang.reflect.Method; 011import java.lang.reflect.Modifier; 012 013/** 014 * Abstract factory class for instantiating BioPAX classes. Different implementations of BioPAX model should also 015 * implement their own factory 016 */ 017 018public abstract class BioPAXFactory 019{ 020 private static final Log log = LogFactory.getLog(BioPAXFactory.class); 021 022 private final Method setUriMethod; 023 024 /** 025 * Protected Constructor without parameters. 026 */ 027 protected BioPAXFactory() { 028 try { 029 setUriMethod = BioPAXElementImpl.class.getDeclaredMethod("setRDFId", String.class); 030 setUriMethod.setAccessible(true); 031 } catch (Throwable e) { 032 throw new RuntimeException("BioPAXFactory Constructor failed", e); 033 } 034 } 035 036 /** 037 * Gets the level. 038 * 039 * @return the biopax level 040 */ 041 public abstract BioPAXLevel getLevel(); 042 043 044 public BioPAXElement create(String localName, String uri) 045 { 046 Class<? extends BioPAXElement> type = getLevel().getInterfaceForName(localName); 047 return create(type, uri); 048 } 049 050 051 /** 052 * Universal method that creates a new BioPAX object. 053 * (works with non-public, other package, implementations) 054 * 055 * @param <T> type 056 * @param aClass the class that corresponds to the BioPAX type 057 * @param uri absolute URI of the new BioPAX object 058 * @return new BioPAX object 059 */ 060 public <T extends BioPAXElement> T create(Class<T> aClass, String uri) { 061 T bpe = null; 062 063 // create a new instance of the BioPAX type 064 try { 065 Class<T> t = getImplClass(aClass); 066 if(t != null) { 067 Constructor<T> c = t.getDeclaredConstructor(); 068 c.setAccessible(true); 069 bpe = (T) c.newInstance(); 070 setUriMethod.invoke(bpe, uri); 071 } else { 072 log.error("Could not find a class implementing " + aClass); 073 return null; 074 } 075 } catch (Exception e) { 076 log.error("Could not instantiate BioPAX Type: " + aClass 077 + "; URI: " + uri, e); 078 } 079 080 return bpe; 081 } 082 083 084 /** 085 * Maps a BioPAX type (model interface) to the 086 * full-qualified class name of an implementing class. 087 * BioPAX factories have to implement this method. 088 * 089 * @param aClass BioPAX type (model interface) 090 * @return full class name 091 */ 092 public abstract String mapClassName(Class<? extends BioPAXElement> aClass); 093 094 095 /** 096 * Checks whether objects of a BioPAX model interface 097 * can be created (some types are not official BioPAX 098 * types, abstract classes). 099 * 100 * @param aClass BioPAX interface class 101 * @return whether this factory can create an instance of the type 102 */ 103 public boolean canInstantiate(Class<? extends BioPAXElement> aClass) 104 { 105 try { 106 String cname = mapClassName(aClass); 107 return !Modifier.isAbstract(Class.forName(cname).getModifiers()); 108 } catch (ClassNotFoundException e) 109 { 110 return false; 111 } catch (Exception ex) { 112 log.error("Error in canInstantiate(" + aClass + ")", ex); 113 return false; 114 } 115 } 116 117 118 /** 119 * Creates a new BioPAX model. 120 * @return BioPAX object model implementation 121 */ 122 public Model createModel() { 123 return new ModelImpl(this); 124 } 125 126 127 /** 128 * Get a concrete or abstract BioPAX type (not interface), 129 * from org.biopax.paxtools.impl..*, i.e., one that has 130 * persistence/search annotations, etc. This may be required for 131 * some DAO and web service controllers; it also returns such 132 * abstract BioPAX "adapters" as XReferrableImpl, ProcessImpl, etc. 133 * 134 * @param <T> BioPAX type/interface 135 * @param aModelInterfaceClass interface class for the BioPAX type 136 * @return concrete class that implements the BioPAX interface and can be created with this factory 137 */ 138 public <T extends BioPAXElement> Class<T> getImplClass( 139 Class<T> aModelInterfaceClass) 140 { 141 Class<T> implClass = null; 142 143 if (aModelInterfaceClass.isInterface()) { 144 String name = mapClassName(aModelInterfaceClass); 145 try { 146 implClass = (Class<T>) Class.forName(name); 147 } catch (ClassNotFoundException e) { 148 log.error(String.format("getImplClass(%s), %s" , aModelInterfaceClass, e)); 149 } 150 } 151 152 return implClass; 153 } 154 155}