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 | * @see org.springframework.xml.transform.StaxSource |
44 | */ |
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 = ClassUtils.getMethodIfAvailable(r.getClass(), "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 = ClassUtils.getMethodIfAvailable(s.getClass(), "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 | } |