001: /*
002: * The contents of this file are subject to the terms of the Common Development
003: * and Distribution License (the License). You may not use this file except in
004: * compliance with the License.
005: *
006: * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
007: * or http://www.netbeans.org/cddl.txt.
008: *
009: * When distributing Covered Code, include this CDDL Header Notice in each file
010: * and include the License file at http://www.netbeans.org/cddl.txt.
011: * If applicable, add the following below the CDDL Header, with the fields
012: * enclosed by brackets [] replaced by your own identifying information:
013: * "Portions Copyrighted [year] [name of copyright owner]"
014: *
015: * The Original Software is NetBeans. The Initial Developer of the Original
016: * Software is Sun Microsystems, Inc. Portions Copyright 2005-2006 Sun
017: * Microsystems, Inc. All Rights Reserved.
018: */
019:
020: package org.netbeans.modules.tcpmon.integration;
021:
022: import java.io.BufferedOutputStream;
023: import java.io.ByteArrayInputStream;
024: import java.io.ByteArrayOutputStream;
025: import java.io.File;
026: import java.io.IOException;
027: import java.io.InputStream;
028: import java.io.OutputStream;
029: import java.net.URISyntaxException;
030: import java.net.URL;
031: import java.util.HashMap;
032: import java.util.Map;
033: import javax.xml.transform.Transformer;
034: import javax.xml.transform.TransformerException;
035: import javax.xml.transform.TransformerFactory;
036: import javax.xml.transform.stream.StreamResult;
037: import javax.xml.transform.stream.StreamSource;
038: import org.netbeans.api.project.ProjectManager;
039: import org.netbeans.spi.project.support.ant.AntProjectHelper;
040: import org.openide.ErrorManager;
041: import org.openide.filesystems.FileLock;
042: import org.openide.filesystems.FileObject;
043: import org.openide.filesystems.FileSystem;
044: import org.openide.filesystems.FileUtil;
045: import org.openide.util.Mutex;
046: import org.openide.util.MutexException;
047: import org.openide.util.UserQuestionException;
048: import org.openide.util.Utilities;
049:
050: /**
051: *
052: * @author Lukas Jungmann
053: */
054: public class BuildScriptGenerator {
055:
056: /** Project directory. */
057: private final FileObject dir;
058:
059: public BuildScriptGenerator(FileObject d) {
060: if (d == null
061: || !d.isFolder()
062: || d.getFileObject(AntProjectHelper.PROJECT_XML_PATH) == null) {
063: throw new IllegalArgumentException(
064: "Does not look like an Ant-based project: " + d); // NOI18N
065: }
066: dir = d;
067: }
068:
069: public void generateBuildScriptFromStylesheet(final String path,
070: final URL stylesheet, final FileObject jaxWsFo,
071: final String wsClients) throws IOException,
072: IllegalStateException {
073: if (path == null) {
074: throw new IllegalArgumentException("Null path"); // NOI18N
075: }
076: if (stylesheet == null) {
077: throw new IllegalArgumentException("Null stylesheet"); // NOI18N
078: }
079: try {
080: ProjectManager.mutex().writeAccess(
081: new Mutex.ExceptionAction() {
082: public Object run() throws IOException {
083: // if (h != null && h.isProjectXmlModified()) {
084: // throw new IllegalStateException("Cannot generate build scripts from a modified project"); // NOI18N
085: // }
086: // Need to use an atomic action since otherwise creating new build scripts might
087: // cause them to not be recognized as Ant scripts.
088: dir.getFileSystem().runAtomicAction(
089: new FileSystem.AtomicAction() {
090: public void run()
091: throws IOException {
092:
093: FileObject projectXml = dir
094: .getFileObject(AntProjectHelper.PROJECT_XML_PATH);
095: final FileObject buildScriptXml = FileUtil
096: .createData(dir,
097: path);
098: byte[] projectXmlData;
099: InputStream is = projectXml
100: .getInputStream();
101: try {
102: projectXmlData = load(is);
103: } finally {
104: is.close();
105: }
106: byte[] stylesheetData;
107: is = stylesheet
108: .openStream();
109: try {
110: stylesheetData = load(is);
111: } finally {
112: is.close();
113: }
114: final byte[] resultData;
115: FileObject jaxWsFileObject = jaxWsFo;
116: if (jaxWsFo == null
117: || !jaxWsFo
118: .isValid()) {
119: jaxWsFileObject = dir
120: .getFileObject("nbproject/jax-ws.xml");
121: }
122:
123: TransformerFactory tf = TransformerFactory
124: .newInstance();
125: try {
126: StreamSource stylesheetSource = new StreamSource(
127: new ByteArrayInputStream(
128: stylesheetData),
129: stylesheet
130: .toExternalForm());
131: Transformer t = tf
132: .newTransformer(stylesheetSource);
133: if (jaxWsFileObject != null)
134: t
135: .setParameter(
136: "jax_ws_uri",
137: jaxWsFileObject
138: .getURL()
139: .toURI()
140: .toASCIIString()); //NOI18N
141: t.setParameter(
142: "wsClients",
143: wsClients);
144: File projectXmlF = FileUtil
145: .toFile(projectXml);
146: assert projectXmlF != null;
147: StreamSource projectXmlSource = new StreamSource(
148: new ByteArrayInputStream(
149: projectXmlData),
150: projectXmlF
151: .toURI()
152: .toString());
153: ByteArrayOutputStream result = new ByteArrayOutputStream();
154: t
155: .transform(
156: projectXmlSource,
157: new StreamResult(
158: result));
159: resultData = result
160: .toByteArray();
161: } catch (TransformerException e) {
162: throw (IOException) new IOException(
163: e.toString())
164: .initCause(e);
165: } catch (URISyntaxException e) {
166: throw (IOException) new IOException(
167: e.toString())
168: .initCause(e);
169: }
170:
171: // You get the Spaghetti Code Award if you can follow the control flow in this method!
172: // Now is the time when you wish Java implemented call/cc.
173: // If you didn't understand that last comment, you don't get the Spaghetti Code Award.
174: final FileSystem.AtomicAction body = new FileSystem.AtomicAction() {
175: public void run()
176: throws IOException {
177: // Try to acquire both locks together, since we need them both written.
178: FileLock lock1 = buildScriptXml
179: .lock();
180: try {
181: OutputStream os1 = new EolFilterOutputStream(
182: buildScriptXml
183: .getOutputStream(lock1));
184: try {
185: os1
186: .write(resultData);
187: } finally {
188: os1.close();
189: }
190: } finally {
191: lock1
192: .releaseLock();
193: }
194: }
195: };
196: try {
197: body.run();
198: } catch (UserQuestionException uqe) {
199: // #57480: need to regenerate build-impl.xml, really.
200: UserQuestionHandler
201: .handle(
202: uqe,
203: new UserQuestionHandler.Callback() {
204: public void accepted() {
205: // Try again.
206: try {
207: body
208: .run();
209: } catch (UserQuestionException uqe2) {
210: // Need to try one more time - may have locked bSX but not yet gf.
211: UserQuestionHandler
212: .handle(
213: uqe2,
214: new UserQuestionHandler.Callback() {
215: public void accepted() {
216: try {
217: body
218: .run();
219: } catch (IOException e) {
220: ErrorManager
221: .getDefault()
222: .notify(
223: e);
224: }
225: }
226:
227: public void denied() {
228: }
229:
230: public void error(
231: IOException e) {
232: ErrorManager
233: .getDefault()
234: .notify(
235: e);
236: }
237: });
238: } catch (IOException e) {
239: // Oh well.
240: ErrorManager
241: .getDefault()
242: .notify(
243: e);
244: }
245: }
246:
247: public void denied() {
248: // OK, skip it.
249: }
250:
251: public void error(
252: IOException e) {
253: ErrorManager
254: .getDefault()
255: .notify(
256: e);
257: // Never mind.
258: }
259: });
260: }
261: }
262: });
263: return null;
264: }
265: });
266: } catch (MutexException e) {
267: throw (IOException) e.getException();
268: }
269: }
270:
271: /**
272: * Load data from a stream into a buffer.
273: */
274: private static byte[] load(InputStream is) throws IOException {
275: int size = Math.max(1024, is.available()); // #46235
276: ByteArrayOutputStream baos = new ByteArrayOutputStream(size);
277: byte[] buf = new byte[size];
278: int read;
279: while ((read = is.read(buf)) != -1) {
280: baos.write(buf, 0, read);
281: }
282: return baos.toByteArray();
283: }
284:
285: // #45373 - workaround: on Windows make sure that all lines end with CRLF.
286: // marcow: Use at least some buffered output!
287: private static class EolFilterOutputStream extends
288: BufferedOutputStream {
289:
290: private boolean isActive = Utilities.isWindows();
291: private int last = -1;
292:
293: public EolFilterOutputStream(OutputStream os) {
294: super (os, 4096);
295: }
296:
297: public void write(byte[] b, int off, int len)
298: throws IOException {
299: if (isActive) {
300: for (int i = off; i < off + len; i++) {
301: write(b[i]);
302: }
303: } else {
304: super .write(b, off, len);
305: }
306: }
307:
308: public void write(int b) throws IOException {
309: if (isActive) {
310: if (b == '\n' && last != '\r') {
311: super .write('\r');
312: }
313: last = b;
314: }
315: super.write(b);
316: }
317: }
318: }
|