1 | /*
|
---|
2 | * Copyright 2000-2004 The Apache Software Foundation
|
---|
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 |
|
---|
18 | package org.apache.tools.ant.taskdefs.optional.ejb;
|
---|
19 |
|
---|
20 | import java.io.File;
|
---|
21 | import java.io.FileInputStream;
|
---|
22 | import java.io.FileNotFoundException;
|
---|
23 | import java.io.IOException;
|
---|
24 | import java.io.InputStream;
|
---|
25 | import java.net.URL;
|
---|
26 | import java.util.Hashtable;
|
---|
27 | import org.apache.tools.ant.Project;
|
---|
28 | import org.apache.tools.ant.Task;
|
---|
29 | import org.xml.sax.AttributeList;
|
---|
30 | import org.xml.sax.InputSource;
|
---|
31 | import org.xml.sax.SAXException;
|
---|
32 |
|
---|
33 | /**
|
---|
34 | * Inner class used by EjbJar to facilitate the parsing of deployment
|
---|
35 | * descriptors and the capture of appropriate information. Extends
|
---|
36 | * HandlerBase so it only implements the methods needed. During parsing
|
---|
37 | * creates a hashtable consisting of entries mapping the name it should be
|
---|
38 | * inserted into an EJB jar as to a File representing the file on disk. This
|
---|
39 | * list can then be accessed through the getFiles() method.
|
---|
40 | */
|
---|
41 | public class DescriptorHandler extends org.xml.sax.HandlerBase {
|
---|
42 | private static final int STATE_LOOKING_EJBJAR = 1;
|
---|
43 | private static final int STATE_IN_EJBJAR = 2;
|
---|
44 | private static final int STATE_IN_BEANS = 3;
|
---|
45 | private static final int STATE_IN_SESSION = 4;
|
---|
46 | private static final int STATE_IN_ENTITY = 5;
|
---|
47 | private static final int STATE_IN_MESSAGE = 6;
|
---|
48 |
|
---|
49 | private Task owningTask;
|
---|
50 |
|
---|
51 | private String publicId = null;
|
---|
52 |
|
---|
53 | /**
|
---|
54 | * Bunch of constants used for storing entries in a hashtable, and for
|
---|
55 | * constructing the filenames of various parts of the ejb jar.
|
---|
56 | */
|
---|
57 | private static final String EJB_REF = "ejb-ref";
|
---|
58 | private static final String EJB_LOCAL_REF = "ejb-local-ref";
|
---|
59 | private static final String HOME_INTERFACE = "home";
|
---|
60 | private static final String REMOTE_INTERFACE = "remote";
|
---|
61 | private static final String LOCAL_HOME_INTERFACE = "local-home";
|
---|
62 | private static final String LOCAL_INTERFACE = "local";
|
---|
63 | private static final String BEAN_CLASS = "ejb-class";
|
---|
64 | private static final String PK_CLASS = "prim-key-class";
|
---|
65 | private static final String EJB_NAME = "ejb-name";
|
---|
66 | private static final String EJB_JAR = "ejb-jar";
|
---|
67 | private static final String ENTERPRISE_BEANS = "enterprise-beans";
|
---|
68 | private static final String ENTITY_BEAN = "entity";
|
---|
69 | private static final String SESSION_BEAN = "session";
|
---|
70 | private static final String MESSAGE_BEAN = "message-driven";
|
---|
71 |
|
---|
72 | /**
|
---|
73 | * The state of the parsing
|
---|
74 | */
|
---|
75 | private int parseState = STATE_LOOKING_EJBJAR;
|
---|
76 |
|
---|
77 | /**
|
---|
78 | * Instance variable used to store the name of the current element being
|
---|
79 | * processed by the SAX parser. Accessed by the SAX parser call-back methods
|
---|
80 | * startElement() and endElement().
|
---|
81 | */
|
---|
82 | protected String currentElement = null;
|
---|
83 |
|
---|
84 | /**
|
---|
85 | * The text of the current element
|
---|
86 | */
|
---|
87 | protected String currentText = null;
|
---|
88 |
|
---|
89 | /**
|
---|
90 | * Instance variable that stores the names of the files as they will be
|
---|
91 | * put into the jar file, mapped to File objects Accessed by the SAX
|
---|
92 | * parser call-back method characters().
|
---|
93 | */
|
---|
94 | protected Hashtable ejbFiles = null;
|
---|
95 |
|
---|
96 | /**
|
---|
97 | * Instance variable that stores the value found in the <ejb-name> element
|
---|
98 | */
|
---|
99 | protected String ejbName = null;
|
---|
100 |
|
---|
101 | private Hashtable fileDTDs = new Hashtable();
|
---|
102 |
|
---|
103 | private Hashtable resourceDTDs = new Hashtable();
|
---|
104 |
|
---|
105 | private boolean inEJBRef = false;
|
---|
106 |
|
---|
107 | private Hashtable urlDTDs = new Hashtable();
|
---|
108 |
|
---|
109 | /**
|
---|
110 | * The directory containing the bean classes and interfaces. This is
|
---|
111 | * used for performing dependency file lookups.
|
---|
112 | */
|
---|
113 | private File srcDir;
|
---|
114 |
|
---|
115 | public DescriptorHandler(Task task, File srcDir) {
|
---|
116 | this.owningTask = task;
|
---|
117 | this.srcDir = srcDir;
|
---|
118 | }
|
---|
119 |
|
---|
120 | public void registerDTD(String publicId, String location) {
|
---|
121 | if (location == null) {
|
---|
122 | return;
|
---|
123 | }
|
---|
124 |
|
---|
125 | File fileDTD = new File(location);
|
---|
126 | if (!fileDTD.exists()) {
|
---|
127 | // resolve relative to project basedir
|
---|
128 | fileDTD = owningTask.getProject().resolveFile(location);
|
---|
129 | }
|
---|
130 |
|
---|
131 | if (fileDTD.exists()) {
|
---|
132 | if (publicId != null) {
|
---|
133 | fileDTDs.put(publicId, fileDTD);
|
---|
134 | owningTask.log("Mapped publicId " + publicId + " to file "
|
---|
135 | + fileDTD, Project.MSG_VERBOSE);
|
---|
136 | }
|
---|
137 | return;
|
---|
138 | }
|
---|
139 |
|
---|
140 | if (getClass().getResource(location) != null) {
|
---|
141 | if (publicId != null) {
|
---|
142 | resourceDTDs.put(publicId, location);
|
---|
143 | owningTask.log("Mapped publicId " + publicId + " to resource "
|
---|
144 | + location, Project.MSG_VERBOSE);
|
---|
145 | }
|
---|
146 | }
|
---|
147 |
|
---|
148 | try {
|
---|
149 | if (publicId != null) {
|
---|
150 | URL urldtd = new URL(location);
|
---|
151 | urlDTDs.put(publicId, urldtd);
|
---|
152 | }
|
---|
153 | } catch (java.net.MalformedURLException e) {
|
---|
154 | //ignored
|
---|
155 | }
|
---|
156 |
|
---|
157 | }
|
---|
158 |
|
---|
159 | public InputSource resolveEntity(String publicId, String systemId)
|
---|
160 | throws SAXException {
|
---|
161 | this.publicId = publicId;
|
---|
162 |
|
---|
163 | File dtdFile = (File) fileDTDs.get(publicId);
|
---|
164 | if (dtdFile != null) {
|
---|
165 | try {
|
---|
166 | owningTask.log("Resolved " + publicId + " to local file "
|
---|
167 | + dtdFile, Project.MSG_VERBOSE);
|
---|
168 | return new InputSource(new FileInputStream(dtdFile));
|
---|
169 | } catch (FileNotFoundException ex) {
|
---|
170 | // ignore
|
---|
171 | }
|
---|
172 | }
|
---|
173 |
|
---|
174 | String dtdResourceName = (String) resourceDTDs.get(publicId);
|
---|
175 | if (dtdResourceName != null) {
|
---|
176 | InputStream is = this.getClass().getResourceAsStream(dtdResourceName);
|
---|
177 | if (is != null) {
|
---|
178 | owningTask.log("Resolved " + publicId + " to local resource "
|
---|
179 | + dtdResourceName, Project.MSG_VERBOSE);
|
---|
180 | return new InputSource(is);
|
---|
181 | }
|
---|
182 | }
|
---|
183 |
|
---|
184 | URL dtdUrl = (URL) urlDTDs.get(publicId);
|
---|
185 | if (dtdUrl != null) {
|
---|
186 | try {
|
---|
187 | InputStream is = dtdUrl.openStream();
|
---|
188 | owningTask.log("Resolved " + publicId + " to url "
|
---|
189 | + dtdUrl, Project.MSG_VERBOSE);
|
---|
190 | return new InputSource(is);
|
---|
191 | } catch (IOException ioe) {
|
---|
192 | //ignore
|
---|
193 | }
|
---|
194 | }
|
---|
195 |
|
---|
196 | owningTask.log("Could not resolve ( publicId: " + publicId
|
---|
197 | + ", systemId: " + systemId + ") to a local entity", Project.MSG_INFO);
|
---|
198 |
|
---|
199 | return null;
|
---|
200 | }
|
---|
201 |
|
---|
202 | /**
|
---|
203 | * Getter method that returns the set of files to include in the EJB jar.
|
---|
204 | */
|
---|
205 | public Hashtable getFiles() {
|
---|
206 | return (ejbFiles == null) ? new Hashtable() : ejbFiles;
|
---|
207 | }
|
---|
208 |
|
---|
209 | /**
|
---|
210 | * Get the publicId of the DTD
|
---|
211 | */
|
---|
212 | public String getPublicId() {
|
---|
213 | return publicId;
|
---|
214 | }
|
---|
215 |
|
---|
216 | /**
|
---|
217 | * Getter method that returns the value of the <ejb-name> element.
|
---|
218 | */
|
---|
219 | public String getEjbName() {
|
---|
220 | return ejbName;
|
---|
221 | }
|
---|
222 |
|
---|
223 | /**
|
---|
224 | * SAX parser call-back method that is used to initialize the values of some
|
---|
225 | * instance variables to ensure safe operation.
|
---|
226 | */
|
---|
227 | public void startDocument() throws SAXException {
|
---|
228 | this.ejbFiles = new Hashtable(10, 1);
|
---|
229 | this.currentElement = null;
|
---|
230 | inEJBRef = false;
|
---|
231 | }
|
---|
232 |
|
---|
233 |
|
---|
234 | /**
|
---|
235 | * SAX parser call-back method that is invoked when a new element is entered
|
---|
236 | * into. Used to store the context (attribute name) in the currentAttribute
|
---|
237 | * instance variable.
|
---|
238 | * @param name The name of the element being entered.
|
---|
239 | * @param attrs Attributes associated to the element.
|
---|
240 | */
|
---|
241 | public void startElement(String name, AttributeList attrs)
|
---|
242 | throws SAXException {
|
---|
243 | this.currentElement = name;
|
---|
244 | currentText = "";
|
---|
245 | if (name.equals(EJB_REF) || name.equals(EJB_LOCAL_REF)) {
|
---|
246 | inEJBRef = true;
|
---|
247 | } else if (parseState == STATE_LOOKING_EJBJAR && name.equals(EJB_JAR)) {
|
---|
248 | parseState = STATE_IN_EJBJAR;
|
---|
249 | } else if (parseState == STATE_IN_EJBJAR && name.equals(ENTERPRISE_BEANS)) {
|
---|
250 | parseState = STATE_IN_BEANS;
|
---|
251 | } else if (parseState == STATE_IN_BEANS && name.equals(SESSION_BEAN)) {
|
---|
252 | parseState = STATE_IN_SESSION;
|
---|
253 | } else if (parseState == STATE_IN_BEANS && name.equals(ENTITY_BEAN)) {
|
---|
254 | parseState = STATE_IN_ENTITY;
|
---|
255 | } else if (parseState == STATE_IN_BEANS && name.equals(MESSAGE_BEAN)) {
|
---|
256 | parseState = STATE_IN_MESSAGE;
|
---|
257 | }
|
---|
258 | }
|
---|
259 |
|
---|
260 |
|
---|
261 | /**
|
---|
262 | * SAX parser call-back method that is invoked when an element is exited.
|
---|
263 | * Used to blank out (set to the empty string, not nullify) the name of
|
---|
264 | * the currentAttribute. A better method would be to use a stack as an
|
---|
265 | * instance variable, however since we are only interested in leaf-node
|
---|
266 | * data this is a simpler and workable solution.
|
---|
267 | * @param name The name of the attribute being exited. Ignored
|
---|
268 | * in this implementation.
|
---|
269 | */
|
---|
270 | public void endElement(String name) throws SAXException {
|
---|
271 | processElement();
|
---|
272 | currentText = "";
|
---|
273 | this.currentElement = "";
|
---|
274 | if (name.equals(EJB_REF) || name.equals(EJB_LOCAL_REF)) {
|
---|
275 | inEJBRef = false;
|
---|
276 | } else if (parseState == STATE_IN_ENTITY && name.equals(ENTITY_BEAN)) {
|
---|
277 | parseState = STATE_IN_BEANS;
|
---|
278 | } else if (parseState == STATE_IN_SESSION && name.equals(SESSION_BEAN)) {
|
---|
279 | parseState = STATE_IN_BEANS;
|
---|
280 | } else if (parseState == STATE_IN_MESSAGE && name.equals(MESSAGE_BEAN)) {
|
---|
281 | parseState = STATE_IN_BEANS;
|
---|
282 | } else if (parseState == STATE_IN_BEANS && name.equals(ENTERPRISE_BEANS)) {
|
---|
283 | parseState = STATE_IN_EJBJAR;
|
---|
284 | } else if (parseState == STATE_IN_EJBJAR && name.equals(EJB_JAR)) {
|
---|
285 | parseState = STATE_LOOKING_EJBJAR;
|
---|
286 | }
|
---|
287 | }
|
---|
288 |
|
---|
289 | /**
|
---|
290 | * SAX parser call-back method invoked whenever characters are located within
|
---|
291 | * an element. currentAttribute (modified by startElement and endElement)
|
---|
292 | * tells us whether we are in an interesting element (one of the up to four
|
---|
293 | * classes of an EJB). If so then converts the classname from the format
|
---|
294 | * org.apache.tools.ant.Parser to the convention for storing such a class,
|
---|
295 | * org/apache/tools/ant/Parser.class. This is then resolved into a file
|
---|
296 | * object under the srcdir which is stored in a Hashtable.
|
---|
297 | * @param ch A character array containing all the characters in
|
---|
298 | * the element, and maybe others that should be ignored.
|
---|
299 | * @param start An integer marking the position in the char
|
---|
300 | * array to start reading from.
|
---|
301 | * @param length An integer representing an offset into the
|
---|
302 | * char array where the current data terminates.
|
---|
303 | */
|
---|
304 | public void characters(char[] ch, int start, int length)
|
---|
305 | throws SAXException {
|
---|
306 |
|
---|
307 | currentText += new String(ch, start, length);
|
---|
308 | }
|
---|
309 |
|
---|
310 |
|
---|
311 | protected void processElement() {
|
---|
312 | if (inEJBRef
|
---|
313 | || (parseState != STATE_IN_ENTITY
|
---|
314 | && parseState != STATE_IN_SESSION
|
---|
315 | && parseState != STATE_IN_MESSAGE)) {
|
---|
316 | return;
|
---|
317 | }
|
---|
318 |
|
---|
319 | if (currentElement.equals(HOME_INTERFACE)
|
---|
320 | || currentElement.equals(REMOTE_INTERFACE)
|
---|
321 | || currentElement.equals(LOCAL_INTERFACE)
|
---|
322 | || currentElement.equals(LOCAL_HOME_INTERFACE)
|
---|
323 | || currentElement.equals(BEAN_CLASS)
|
---|
324 | || currentElement.equals(PK_CLASS)) {
|
---|
325 |
|
---|
326 | // Get the filename into a String object
|
---|
327 | File classFile = null;
|
---|
328 | String className = currentText.trim();
|
---|
329 |
|
---|
330 | // If it's a primitive wrapper then we shouldn't try and put
|
---|
331 | // it into the jar, so ignore it.
|
---|
332 | if (!className.startsWith("java.")
|
---|
333 | && !className.startsWith("javax.")) {
|
---|
334 | // Translate periods into path separators, add .class to the
|
---|
335 | // name, create the File object and add it to the Hashtable.
|
---|
336 | className = className.replace('.', File.separatorChar);
|
---|
337 | className += ".class";
|
---|
338 | classFile = new File(srcDir, className);
|
---|
339 | ejbFiles.put(className, classFile);
|
---|
340 | }
|
---|
341 | }
|
---|
342 |
|
---|
343 | // Get the value of the <ejb-name> tag. Only the first occurrence.
|
---|
344 | if (currentElement.equals(EJB_NAME)) {
|
---|
345 | if (ejbName == null) {
|
---|
346 | ejbName = currentText.trim();
|
---|
347 | }
|
---|
348 | }
|
---|
349 | }
|
---|
350 | }
|
---|