001: /*
002: * This file is part of PFIXCORE.
003: *
004: * PFIXCORE is free software; you can redistribute it and/or modify
005: * it under the terms of the GNU Lesser General Public License as published by
006: * the Free Software Foundation; either version 2 of the License, or
007: * (at your option) any later version.
008: *
009: * PFIXCORE is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012: * GNU Lesser General Public License for more details.
013: *
014: * You should have received a copy of the GNU Lesser General Public License
015: * along with PFIXCORE; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: *
018: */
019: package de.schlund.pfixcore.webservice.jaxws.generate;
020:
021: import java.io.File;
022: import java.io.IOException;
023: import java.lang.reflect.GenericArrayType;
024: import java.lang.reflect.Method;
025: import java.lang.reflect.ParameterizedType;
026: import java.lang.reflect.Type;
027: import java.lang.reflect.TypeVariable;
028: import java.lang.reflect.WildcardType;
029: import java.net.JarURLConnection;
030: import java.net.URL;
031:
032: import javax.xml.parsers.DocumentBuilder;
033: import javax.xml.parsers.DocumentBuilderFactory;
034:
035: import org.apache.tools.ant.AntClassLoader;
036: import org.apache.tools.ant.BuildException;
037: import org.w3c.dom.Document;
038:
039: /**
040: * Common utility methods used by the ant tasks
041: *
042: * @author mleidig@schlund.de
043: */
044: public class TaskUtils {
045:
046: /**
047: * Returns the default target namespace of a class as defined in the JAX-WS
048: * specification. The namespace is derived from the package of the class
049: * using {@link #getTargetNamespace(Package)}.
050: *
051: * @param clazz the Java class
052: * @return the default target namespace
053: */
054: public static String getTargetNamespace(Class<?> clazz) {
055: if (clazz == null)
056: throw new IllegalArgumentException(
057: "Class argument must not be null");
058: return getTargetNamespace(clazz.getPackage());
059: }
060:
061: /**
062: * Returns the default target namespace of a package as defined in the
063: * JAX-WS specification.
064: *
065: * @param pkg the Java package
066: * @return the default target namespace
067: */
068: public static String getTargetNamespace(Package pkg) {
069: if (pkg == null)
070: throw new IllegalArgumentException(
071: "Class has no package information");
072: StringBuilder sb = new StringBuilder();
073: sb.append("http://");
074: String name = pkg.getName();
075: String[] pkgs = name.split("\\.");
076: for (int i = pkgs.length - 1; i > -1; i--) {
077: sb.append(pkgs[i]);
078: if (i > 0)
079: sb.append(".");
080: }
081: sb.append("/");
082: return sb.toString();
083: }
084:
085: /**
086: * Checks if the webservice interface has been modified since the last
087: * modification of a reference file.
088: */
089: public static boolean checkInterfaceChange(String className,
090: File buildDir, File refFile) throws BuildException {
091: try {
092: Class<?> clazz = Class.forName(className);
093: if (!clazz.isInterface())
094: throw new BuildException(
095: "Web service interface class '" + className
096: + "' doesn't define an interface type.");
097: // Check if interface or dependant interfaces changed
098: boolean changed = checkTypeChange(clazz, buildDir, refFile);
099: if (changed)
100: return true;
101: // Check if method parameter or return type classes changed
102: Method[] meths = clazz.getMethods();
103: for (int i = 0; i < meths.length; i++) {
104: Class<?> ret = meths[i].getReturnType();
105: changed = checkTypeChange(ret, buildDir, refFile);
106: if (changed)
107: return true;
108: Class<?>[] pars = meths[i].getParameterTypes();
109: for (int j = 0; j < pars.length; j++) {
110: changed = checkTypeChange(pars[j], buildDir,
111: refFile);
112: if (changed)
113: return true;
114: }
115: }
116: return false;
117: } catch (ClassNotFoundException x) {
118: throw new BuildException("Web service interface class '"
119: + className + "' not found.", x);
120: }
121: }
122:
123: /**
124: * Checks if a class has been modified since the last modification of a
125: * reference file.
126: */
127: public static boolean checkTypeChange(Class<?> clazz,
128: File buildDir, File refFile) {
129: if (!clazz.isPrimitive()) {
130: ClassLoader cl = clazz.getClassLoader();
131: if (cl instanceof AntClassLoader) {
132: if (clazz.isArray())
133: return checkTypeChange(getArrayType(clazz),
134: buildDir, refFile);
135: String path = clazz.getName().replace('.',
136: File.separatorChar)
137: + ".class";
138: File file = new File(buildDir, path);
139: long lastMod = Long.MAX_VALUE;
140: if (!file.exists()) {
141: URL url = cl.getResource(path);
142: if (url == null)
143: throw new BuildException(
144: "Can't get URL for webservice class '"
145: + clazz.getName()
146: + "' from jar file.");
147: else {
148: try {
149: JarURLConnection con = (JarURLConnection) url
150: .openConnection();
151: lastMod = con.getJarEntry().getTime();
152: } catch (IOException x) {
153: throw new BuildException(
154: "Can't get modification time for webservice class '"
155: + clazz.getName()
156: + "' from jar file.");
157: }
158: }
159: } else {
160: lastMod = file.lastModified();
161: }
162: if (refFile.lastModified() < lastMod)
163: return true;
164: if (clazz.isInterface()) {
165: Class<?>[] itfs = clazz.getInterfaces();
166: for (int i = 0; i < itfs.length; i++) {
167: boolean changed = checkTypeChange(itfs[i],
168: buildDir, refFile);
169: if (changed)
170: return true;
171: }
172: } else {
173: Class<?> sup = clazz.getSuperclass();
174: boolean changed = checkTypeChange(sup, buildDir,
175: refFile);
176: if (changed)
177: return true;
178: }
179: }
180: }
181: return false;
182: }
183:
184: /**
185: * Get the root component type of an array (with arbitrary dimensions)
186: */
187: public static Class<?> getArrayType(Class<?> clazz) {
188: if (clazz.isArray())
189: return getArrayType(clazz.getComponentType());
190: else
191: return clazz;
192: }
193:
194: /**
195: * Checks if the method's return or parameter types contain an interface
196: * (which isn't supported by JAXB)
197: */
198: public static boolean hasInterfaceType(Method method) {
199: if (method.getReturnType().isInterface())
200: return true;
201: Class<?>[] types = method.getParameterTypes();
202: for (Class<?> type : types) {
203: if (isInterfaceType(type))
204: return true;
205: }
206: return false;
207: }
208:
209: /**
210: * Checks if class is an interface or an array of an interface type
211: */
212: private static boolean isInterfaceType(Class<?> clazz) {
213: if (clazz.isArray())
214: return isInterfaceType(clazz.getComponentType());
215: return clazz.isInterface();
216: }
217:
218: /**
219: * Creates string representation of Java type (in source code form)
220: */
221: public static String getTypeString(Type type) {
222: if (type instanceof ParameterizedType) {
223: ParameterizedType paramType = (ParameterizedType) type;
224: Type rawType = paramType.getRawType();
225: String str = getTypeString(rawType);
226: Type[] typeArgs = paramType.getActualTypeArguments();
227: str += "<";
228: for (int i = 0; i < typeArgs.length; i++) {
229: if (i > 0)
230: str += ",";
231: str += getTypeString(typeArgs[i]);
232: }
233: str += ">";
234: return str;
235: } else if (type instanceof GenericArrayType) {
236: GenericArrayType arrayType = (GenericArrayType) type;
237: Type compType = arrayType.getGenericComponentType();
238: return getTypeString(compType) + "[]";
239: } else if (type instanceof WildcardType) {
240: WildcardType wildType = (WildcardType) type;
241: Type[] lowerTypes = wildType.getLowerBounds();
242: String str = "";
243: if (lowerTypes.length == 1) {
244: str += "? super ";
245: str += getTypeString(lowerTypes[0]);
246: } else if (lowerTypes.length > 1)
247: throw new RuntimeException(
248: "Multiple lower bounds aren't supported");
249: Type[] upperTypes = wildType.getUpperBounds();
250: if (upperTypes.length == 1) {
251: if (upperTypes[0] == Object.class)
252: str += "?";
253: else {
254: if (lowerTypes.length > 0)
255: throw new RuntimeException(
256: "Lower bounds with upper bounds aren't supported");
257: str += "? extends ";
258: str += getTypeString(upperTypes[0]);
259: }
260: } else if (upperTypes.length > 1)
261: throw new RuntimeException(
262: "Multiple upper bounds aren't supported");
263: return str;
264: } else if (type instanceof TypeVariable) {
265: throw new RuntimeException("Not supported");
266: } else {
267: Class<?> clazz = (Class<?>) type;
268: return clazz.getCanonicalName();
269: }
270: }
271:
272: /**
273: * Reads Document from a XML file.
274: */
275: public static Document loadDoc(File file) throws BuildException {
276: try {
277: DocumentBuilderFactory dbf = DocumentBuilderFactory
278: .newInstance();
279: dbf.setNamespaceAware(true);
280: dbf.setValidating(false);
281: DocumentBuilder docBuilder = dbf.newDocumentBuilder();
282: Document doc = docBuilder.parse(file);
283: return doc;
284: } catch (Exception x) {
285: throw new BuildException(
286: "Can't load XML document from file "
287: + file.getAbsolutePath(), x);
288: }
289: }
290:
291: }
|