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 }