View Javadoc

1   /*
2    * Copyright 2006-2007 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.springframework.batch.item.xml;
18  
19  import java.lang.reflect.Constructor;
20  import java.lang.reflect.Method;
21  
22  import javax.xml.stream.XMLEventReader;
23  import javax.xml.stream.XMLEventWriter;
24  import javax.xml.transform.Result;
25  import javax.xml.transform.Source;
26  
27  import org.apache.commons.logging.Log;
28  import org.apache.commons.logging.LogFactory;
29  import org.springframework.util.Assert;
30  import org.springframework.util.ClassUtils;
31  
32  /**
33   * This class provides a little bit of indirection to avoid ugly conditional object creation. It is unfortunately
34   * a bit redundant assuming a Spring 3.0 environment, but is necessary to work with Spring WS 1.5.x.
35   * <p/>
36   * The returned object determines whether the environment has Spring OXM as included in the Spring 3.x series of relies
37   * or whether it has Spring OXM from Spring WS 1.5x and factories a StaxSource instance appropriately.
38   * <p/>
39   * As the only class state maintained is to cache java reflection metadata, which is thread safe, this class is thread-safe.
40   *
41   * @author Josh Long
42   *
43   */
44  @SuppressWarnings("restriction")
45  public abstract class StaxUtils {
46  
47  	private static final Log logger = LogFactory.getLog(StaxUtils.class);
48  
49  	private static ClassLoader defaultClassLoader = ClassUtils.getDefaultClassLoader();
50  
51  	// regular object.
52  	private static String staxSourceClassNameOnSpringWs15 = "org.springframework.xml.transform.StaxSource";
53  	private static String staxResultClassNameOnSpringOxm15 = "org.springframework.xml.transform.StaxResult";
54  
55  	// in Spring 3, StaxUtils is package private, so use static utility StaxUtils#createStaxSource / StaxUtils#createStaxResult
56  	private static String staxSourceClassNameOnSpringOxm30 = "org.springframework.util.xml.StaxUtils";
57  
58  	private static boolean hasSpringWs15StaxSupport = ClassUtils.isPresent(staxSourceClassNameOnSpringWs15, defaultClassLoader);
59  
60  	private static boolean hasSpring30StaxSupport = ClassUtils.isPresent(staxSourceClassNameOnSpringOxm30, defaultClassLoader);
61  
62  	private static Method staxUtilsSourceMethodOnSpring30, staxUtilsResultMethodOnSpring30;
63  
64  	@SuppressWarnings("rawtypes")
65  	private static Constructor staxSourceClassCtorOnSpringWs15, staxResultClassCtorOnSpringWs15;
66  
67  	static {
68  		try {
69  
70  			// cache the factory method / constructor so that we spend as little time in reflection as possible
71  			if (hasSpring30StaxSupport) {
72  				Class<?> clzz = ClassUtils.forName(staxSourceClassNameOnSpringOxm30, defaultClassLoader);
73  
74  				// javax.xml.transform.Source
75  				staxUtilsSourceMethodOnSpring30 = ClassUtils.getStaticMethod(clzz, "createStaxSource", new Class[]{ XMLEventReader.class});
76  
77  				// javax.xml.transform.Result
78  				staxUtilsResultMethodOnSpring30 = ClassUtils.getStaticMethod(clzz, "createStaxResult", new Class[]{XMLEventWriter.class});
79  			} else if (hasSpringWs15StaxSupport) {
80  
81  				// javax.xml.transform.Source
82  				Class<?> staxSourceClassOnSpringWs15 = ClassUtils.forName(staxSourceClassNameOnSpringWs15, defaultClassLoader);
83  				staxSourceClassCtorOnSpringWs15 = staxSourceClassOnSpringWs15.getConstructor(XMLEventReader.class);
84  
85  				// javax.xml.transform.Result
86  				Class<?> staxResultClassOnSpringWs15 = ClassUtils.forName(staxResultClassNameOnSpringOxm15, defaultClassLoader);
87  				staxResultClassCtorOnSpringWs15 = staxResultClassOnSpringWs15.getConstructor(XMLEventWriter.class);
88  			} else {
89  
90  				logger.debug("'StaxSource' was not detected in Spring 3.0's OXM support or Spring WS 1.5's OXM support. " +
91  						"This is a problem if you intend to use the " +StaxEventItemWriter.class.getName() + " or " +
92  						StaxEventItemReader.class.getName()+". Please add the appropriate dependencies.");
93  
94  			}
95  		} catch (Exception ex) {
96  			logger.error("Could not precache required class and method metadata in " + StaxUtils.class.getName());
97  		}
98  	}
99  
100 	public static Source getSource(XMLEventReader r) throws Exception {
101 		if (hasSpring30StaxSupport) {
102 			// org.springframework.util.xml.StaxUtils.createStaxSource(r)
103 			Object result = staxUtilsSourceMethodOnSpring30.invoke(null,r);
104 			Assert.isInstanceOf(Source.class, result, "the result should be assignable to " + Source.class.getName());
105 			return (Source) result;
106 		} else if (hasSpringWs15StaxSupport) {
107 			Object result = staxSourceClassCtorOnSpringWs15.newInstance(r);
108 			Assert.isInstanceOf(Source.class, result, "the result should be assignable to " + Source.class.getName());
109 			return (Source) result;
110 		}
111 		// maybe you don't have either environment?
112 		return null;
113 	}
114 
115 	public static Result getResult(XMLEventWriter w) throws Exception {
116 		if (hasSpring30StaxSupport) {
117 			Object result = staxUtilsResultMethodOnSpring30.invoke(null,w);
118 			Assert.isInstanceOf(Result.class, result, "the result should be assignable to " + Result.class.getName());
119 			return (Result) result;
120 		} else if (hasSpringWs15StaxSupport) {
121 			Object result = staxResultClassCtorOnSpringWs15.newInstance(w);
122 			Assert.isInstanceOf(Result.class, result, "the result should be assignable to " + Result.class.getName());
123 			return (Result) result;
124 		}
125 		// maybe you don't have either environment?
126 		return null;
127 	}
128 
129     public static XMLEventWriter getXmlEventWriter(Result r) throws Exception {
130         Method m = r.getClass().getDeclaredMethod("getXMLEventWriter", new Class[]{});
131         boolean accessible = m.isAccessible();
132         m.setAccessible(true);
133         Object result = m.invoke(r);
134         m.setAccessible(accessible);
135         return (XMLEventWriter) result;
136     }
137 
138     public static XMLEventReader getXmlEventReader(Source s) throws Exception {
139         Method m = s.getClass().getDeclaredMethod("getXMLEventReader", new Class[]{});
140         boolean accessible = m.isAccessible();
141         m.setAccessible(true);
142         Object result = m.invoke(s);
143         m.setAccessible(accessible);
144         return (XMLEventReader) result;
145     }
146 }