001 /* 002 @license.text@ 003 */ 004 package biz.hammurapi.ant; 005 006 import java.lang.reflect.InvocationTargetException; 007 import java.util.Collection; 008 import java.util.Iterator; 009 import java.util.LinkedList; 010 import java.util.List; 011 012 import org.apache.tools.ant.AntClassLoader; 013 import org.apache.tools.ant.BuildException; 014 import org.apache.tools.ant.Task; 015 import org.apache.tools.ant.types.Path; 016 017 import biz.hammurapi.config.ConfigurationException; 018 import biz.hammurapi.config.Parameterizable; 019 020 /** 021 * Object entry. Base class for configurable objects. 022 * @ant.element name="objectentry" 023 * @author Pavel Vlasov 024 * @version $Revision: 1.5 $ 025 */ 026 public class ObjectEntry extends Task { 027 private String className; 028 private String value; 029 private List parameters=new LinkedList(); 030 031 /** 032 * Configuration parameter. Object entry class must implement biz.hammurapi.config.Parameterizable 033 * @ant.non-required 034 * @param parameter 035 * @throws BuildException 036 */ 037 public void addConfiguredParameter(Param parameter) throws BuildException { 038 if (parameter.getName()==null) { 039 throw new BuildException("Unnamed parameter"); 040 } 041 parameters.add(parameter); 042 } 043 044 /** 045 * Either value or class name is required. If both class name and value are 046 * specified then that class should have a constructor with one String parameter. 047 * @ant.non-required 048 * @param className 049 */ 050 public void setClassName(String className) { 051 this.className = className; 052 } 053 054 /** 055 * Not required if class name is set. 056 * @ant.non-required 057 * @param value 058 */ 059 public void setValue(String value) { 060 this.value = value; 061 } 062 063 /** 064 * @ant.ignore 065 * @return 066 */ 067 public Collection getParameters() { 068 return parameters; 069 } 070 071 private Object theObject; 072 073 protected void validateClass(Class clazz) throws BuildException { 074 075 } 076 077 protected void validateInstance(Object instance) throws BuildException { 078 079 } 080 081 public Object getObject(ClassLoader masterClassLoader) throws BuildException { 082 if (theObject==null) { 083 if (className==null) { 084 if (parameters.isEmpty()) { 085 if (value==null) { 086 return null; 087 } 088 theObject=value; 089 } else { 090 throw new BuildException("Nested parameters supported only if classname attribute is set"); 091 } 092 } else { 093 try { 094 ClassLoader classLoader=masterClassLoader==null ? getProject().getCoreLoader() : masterClassLoader; 095 if (classPath!=null) { 096 if (masterClassLoader==null) { 097 classLoader=new AntClassLoader(getProject(), classPath); 098 } else { 099 classLoader=new AntClassLoader(masterClassLoader, getProject(), classPath, false); 100 } 101 } 102 103 if (classLoader==null) { 104 classLoader=getClass().getClassLoader(); 105 } 106 107 Class theClass=classLoader.loadClass(className); 108 validateClass(theClass); 109 if (!(parameters.isEmpty() || Parameterizable.class.isAssignableFrom(theClass))) { 110 throw new BuildException(className+" does not support parameters"); 111 } 112 113 if (value==null) { 114 theObject=theClass.newInstance(); 115 } else { 116 theObject=theClass.getConstructor(new Class[] {String.class}).newInstance(new Object[] {value}); 117 } 118 119 if (!parameters.isEmpty()) { 120 // Double check 121 if (theObject instanceof Parameterizable) { 122 Iterator it=parameters.iterator(); 123 while (it.hasNext()) { 124 Param param=(Param) it.next(); 125 try { 126 if (!((Parameterizable) theObject).setParameter(param.getName(), param.getObject(masterClassLoader))) { 127 throw new BuildException(theObject.getClass().getName()+" does not support parameter "+param.getName()); 128 } 129 } catch (ConfigurationException e) { 130 throw new BuildException("Could not set parameter "+param.getName()+" for object entry "+theObject.getClass().getName(), e); 131 } 132 } 133 } else { 134 throw new BuildException(className+" does not support parameters"); 135 } 136 } 137 validateInstance(theObject); 138 } catch (ClassNotFoundException e) { 139 throw new BuildException("Class not found: "+className, e); 140 } catch (InstantiationException e) { 141 throw new BuildException("Can not instantiate: "+className, e); 142 } catch (IllegalAccessException e) { 143 throw new BuildException("Can not instantiate: "+className, e); 144 } catch (InvocationTargetException e) { 145 throw new BuildException("Can not instantiate: "+className, e); 146 } catch (NoSuchMethodException e) { 147 throw new BuildException("Constructor "+className+"(String) not found", e); 148 } 149 } 150 } 151 return theObject; 152 } 153 /** 154 * @return 155 */ 156 protected String getClassName() { 157 return className; 158 } 159 160 /** 161 * @return 162 */ 163 protected String getValue() { 164 return value; 165 } 166 167 /** 168 * Classpath for loading classes 169 * @ant:non-required 170 */ 171 private Path classPath; 172 173 public void setClassPath(Path classPath) { 174 if (this.classPath == null) { 175 this.classPath = classPath; 176 } else { 177 this.classPath.append(classPath); 178 } 179 } 180 181 /** 182 * Maybe creates a nested classpath element. 183 * @ant:non-required 184 */ 185 public Path createClasspath() { 186 if (classPath == null) { 187 classPath = new Path(getProject()); 188 } 189 return classPath.createPath(); 190 } 191 192 public void addText(String text) { 193 this.value=text; 194 } 195 }