001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.internal.ui.javadocexport;
011:
012: import java.io.BufferedOutputStream;
013: import java.io.File;
014: import java.io.OutputStream;
015: import java.util.ArrayList;
016: import java.util.Iterator;
017: import java.util.List;
018:
019: import javax.xml.parsers.DocumentBuilder;
020: import javax.xml.parsers.DocumentBuilderFactory;
021: import javax.xml.parsers.ParserConfigurationException;
022: import javax.xml.transform.OutputKeys;
023: import javax.xml.transform.Transformer;
024: import javax.xml.transform.TransformerException;
025: import javax.xml.transform.TransformerFactory;
026: import javax.xml.transform.dom.DOMSource;
027: import javax.xml.transform.stream.StreamResult;
028:
029: import org.eclipse.core.runtime.IPath;
030: import org.eclipse.core.runtime.Path;
031:
032: import org.eclipse.core.resources.IProject;
033: import org.eclipse.core.resources.ResourcesPlugin;
034:
035: import org.eclipse.jdt.core.ICompilationUnit;
036: import org.eclipse.jdt.core.IJavaElement;
037: import org.eclipse.jdt.core.IJavaProject;
038: import org.eclipse.jdt.core.IPackageFragment;
039:
040: import org.w3c.dom.DOMException;
041: import org.w3c.dom.Document;
042: import org.w3c.dom.Element;
043:
044: public class JavadocWriter {
045:
046: private static final char PATH_SEPARATOR = '/'; // use forward slash for all platforms
047:
048: private final IJavaProject[] fJavaProjects;
049: private final IPath fBasePath;
050:
051: /**
052: * Create a JavadocWriter.
053: * @param basePath The base path to which all path will be made relative (if
054: * possible). If <code>null</code>, paths are not made relative.
055: * @param projects
056: */
057: public JavadocWriter(IPath basePath, IJavaProject[] projects) {
058: fBasePath = basePath;
059: fJavaProjects = projects;
060: }
061:
062: public Element createXML(JavadocOptionsManager store)
063: throws ParserConfigurationException {
064:
065: DocumentBuilder docBuilder = null;
066: DocumentBuilderFactory factory = DocumentBuilderFactory
067: .newInstance();
068: factory.setValidating(false);
069: docBuilder = factory.newDocumentBuilder();
070: Document document = docBuilder.newDocument();
071:
072: // Create the document
073: Element project = document.createElement("project"); //$NON-NLS-1$
074: document.appendChild(project);
075:
076: project.setAttribute("default", "javadoc"); //$NON-NLS-1$ //$NON-NLS-2$
077:
078: Element javadocTarget = document.createElement("target"); //$NON-NLS-1$
079: project.appendChild(javadocTarget);
080: javadocTarget.setAttribute("name", "javadoc"); //$NON-NLS-1$ //$NON-NLS-2$
081:
082: Element xmlJavadocDesc = document.createElement("javadoc"); //$NON-NLS-1$
083: javadocTarget.appendChild(xmlJavadocDesc);
084:
085: if (!store.isFromStandard())
086: xmlWriteDoclet(store, document, xmlJavadocDesc);
087: else
088: xmlWriteJavadocStandardParams(store, document,
089: xmlJavadocDesc);
090:
091: return xmlJavadocDesc;
092: }
093:
094: /**
095: * Writes the document to the given stream.
096: * It is the client's responsibility to close the output stream.
097: * @param javadocElement the XML element defining the Javadoc tags
098: * @param encoding the encoding to use
099: * @param outputStream the output stream
100: * @throws TransformerException thrown if writing fails
101: */
102: public static void writeDocument(Element javadocElement,
103: String encoding, OutputStream outputStream)
104: throws TransformerException {
105:
106: // Write the document to the stream
107: Transformer transformer = TransformerFactory.newInstance()
108: .newTransformer();
109: transformer.setOutputProperty(OutputKeys.METHOD, "xml"); //$NON-NLS-1$
110: transformer.setOutputProperty(OutputKeys.ENCODING, encoding);
111: transformer.setOutputProperty(OutputKeys.INDENT, "yes"); //$NON-NLS-1$
112: transformer.setOutputProperty(
113: "{http://xml.apache.org/xslt}indent-amount", "4"); //$NON-NLS-1$ //$NON-NLS-2$
114: DOMSource source = new DOMSource(javadocElement
115: .getOwnerDocument());
116: StreamResult result = new StreamResult(
117: new BufferedOutputStream(outputStream));
118: transformer.transform(source, result);
119:
120: }
121:
122: //writes ant file, for now only worry about one project
123: private void xmlWriteJavadocStandardParams(
124: JavadocOptionsManager store, Document document,
125: Element xmlJavadocDesc) throws DOMException {
126:
127: String destination = getPathString(Path.fromOSString(store
128: .getDestination()));
129:
130: xmlJavadocDesc.setAttribute(store.DESTINATION, destination);
131: xmlJavadocDesc
132: .setAttribute(store.VISIBILITY, store.getAccess());
133: String source = store.getSource();
134: if (source.length() > 0 && !source.equals("-")) { //$NON-NLS-1$
135: xmlJavadocDesc
136: .setAttribute(store.SOURCE, store.getSource());
137: }
138: xmlJavadocDesc.setAttribute(store.USE, booleanToString(store
139: .getBoolean("use"))); //$NON-NLS-1$
140: xmlJavadocDesc.setAttribute(store.NOTREE, booleanToString(store
141: .getBoolean("notree"))); //$NON-NLS-1$
142: xmlJavadocDesc.setAttribute(store.NONAVBAR,
143: booleanToString(store.getBoolean("nonavbar"))); //$NON-NLS-1$
144: xmlJavadocDesc.setAttribute(store.NOINDEX,
145: booleanToString(store.getBoolean("noindex"))); //$NON-NLS-1$
146: xmlJavadocDesc.setAttribute(store.SPLITINDEX,
147: booleanToString(store.getBoolean("splitindex"))); //$NON-NLS-1$
148: xmlJavadocDesc.setAttribute(store.AUTHOR, booleanToString(store
149: .getBoolean("author"))); //$NON-NLS-1$
150: xmlJavadocDesc.setAttribute(store.VERSION,
151: booleanToString(store.getBoolean("version"))); //$NON-NLS-1$
152: xmlJavadocDesc.setAttribute(store.NODEPRECATEDLIST,
153: booleanToString(store.getBoolean("nodeprecatedlist"))); //$NON-NLS-1$
154: xmlJavadocDesc.setAttribute(store.NODEPRECATED,
155: booleanToString(store.getBoolean("nodeprecated"))); //$NON-NLS-1$
156:
157: //set the packages and source files
158: List packages = new ArrayList();
159: List sourcefiles = new ArrayList();
160: sortSourceElement(store.getSourceElements(), sourcefiles,
161: packages);
162: if (!packages.isEmpty())
163: xmlJavadocDesc.setAttribute(store.PACKAGENAMES,
164: toSeparatedList(packages));
165:
166: if (!sourcefiles.isEmpty())
167: xmlJavadocDesc.setAttribute(store.SOURCEFILES,
168: toSeparatedList(sourcefiles));
169:
170: xmlJavadocDesc.setAttribute(store.SOURCEPATH,
171: getPathString(store.getSourcepath()));
172: xmlJavadocDesc.setAttribute(store.CLASSPATH,
173: getPathString(store.getClasspath()));
174:
175: String overview = store.getOverview();
176: if (overview.length() > 0)
177: xmlJavadocDesc.setAttribute(store.OVERVIEW, overview);
178:
179: String styleSheet = store.getStyleSheet();
180: if (styleSheet.length() > 0)
181: xmlJavadocDesc.setAttribute(store.STYLESHEETFILE,
182: styleSheet);
183:
184: String title = store.getTitle();
185: if (title.length() > 0)
186: xmlJavadocDesc.setAttribute(store.TITLE, title);
187:
188: String vmArgs = store.getVMParams();
189: String additionalArgs = store.getAdditionalParams();
190: if (vmArgs.length() + additionalArgs.length() > 0) {
191: String str = vmArgs + ' ' + additionalArgs;
192: xmlJavadocDesc.setAttribute(store.EXTRAOPTIONS, str);
193: }
194:
195: String[] hrefs = store.getHRefs();
196: for (int i = 0; i < hrefs.length; i++) {
197: Element links = document.createElement("link"); //$NON-NLS-1$
198: xmlJavadocDesc.appendChild(links);
199: links.setAttribute(store.HREF, hrefs[i]);
200: }
201: }
202:
203: private void sortSourceElement(IJavaElement[] iJavaElements,
204: List sourcefiles, List packages) {
205: for (int i = 0; i < iJavaElements.length; i++) {
206: IJavaElement element = iJavaElements[i];
207: IPath p = element.getResource().getLocation();
208: if (p == null)
209: continue;
210:
211: if (element instanceof ICompilationUnit) {
212: String relative = getPathString(p);
213: sourcefiles.add(relative);
214: } else if (element instanceof IPackageFragment) {
215: packages.add(element.getElementName());
216: }
217: }
218: }
219:
220: private String getPathString(IPath[] paths) {
221: StringBuffer buf = new StringBuffer();
222:
223: for (int i = 0; i < paths.length; i++) {
224: if (buf.length() != 0) {
225: buf.append(File.pathSeparatorChar);
226: }
227: buf.append(getPathString(paths[i]));
228: }
229:
230: if (buf.length() == 0) {
231: buf.append('.');
232: }
233: return buf.toString();
234: }
235:
236: private boolean hasSameDevice(IPath p1, IPath p2) {
237: String dev = p1.getDevice();
238: if (dev == null) {
239: return p2.getDevice() == null;
240: }
241: return dev.equals(p2.getDevice());
242: }
243:
244: //make the path relative to the base path
245: private String getPathString(IPath fullPath) {
246: if (fBasePath == null || !hasSameDevice(fullPath, fBasePath)) {
247: return fullPath.toOSString();
248: }
249: int matchingSegments = fBasePath
250: .matchingFirstSegments(fullPath);
251: if (fBasePath.segmentCount() == matchingSegments) {
252: return getRelativePath(fullPath, matchingSegments);
253: }
254: for (int i = 0; i < fJavaProjects.length; i++) {
255: IProject proj = fJavaProjects[i].getProject();
256: IPath projLoc = proj.getLocation();
257: if (projLoc != null
258: && projLoc.segmentCount() <= matchingSegments
259: && projLoc.isPrefixOf(fullPath)) {
260: return getRelativePath(fullPath, matchingSegments);
261: }
262: }
263: IPath workspaceLoc = ResourcesPlugin.getWorkspace().getRoot()
264: .getLocation();
265: if (workspaceLoc.segmentCount() <= matchingSegments
266: && workspaceLoc.isPrefixOf(fullPath)) {
267: return getRelativePath(fullPath, matchingSegments);
268: }
269: return fullPath.toOSString();
270: }
271:
272: private String getRelativePath(IPath fullPath, int matchingSegments) {
273: StringBuffer res = new StringBuffer();
274: int backSegments = fBasePath.segmentCount() - matchingSegments;
275: while (backSegments > 0) {
276: res.append(".."); //$NON-NLS-1$
277: res.append(PATH_SEPARATOR);
278: backSegments--;
279: }
280: int segCount = fullPath.segmentCount();
281: for (int i = matchingSegments; i < segCount; i++) {
282: if (i > matchingSegments) {
283: res.append(PATH_SEPARATOR);
284: }
285: res.append(fullPath.segment(i));
286: }
287: return res.toString();
288: }
289:
290: private void xmlWriteDoclet(JavadocOptionsManager store,
291: Document document, Element xmlJavadocDesc)
292: throws DOMException {
293:
294: //set the packages and source files
295: List packages = new ArrayList();
296: List sourcefiles = new ArrayList();
297: sortSourceElement(store.getSourceElements(), sourcefiles,
298: packages);
299: if (!packages.isEmpty())
300: xmlJavadocDesc.setAttribute(store.PACKAGENAMES,
301: toSeparatedList(packages));
302:
303: if (!sourcefiles.isEmpty())
304: xmlJavadocDesc.setAttribute(store.SOURCEFILES,
305: toSeparatedList(sourcefiles));
306:
307: xmlJavadocDesc.setAttribute(store.SOURCEPATH,
308: getPathString(store.getSourcepath()));
309: xmlJavadocDesc.setAttribute(store.CLASSPATH,
310: getPathString(store.getClasspath()));
311: xmlJavadocDesc
312: .setAttribute(store.VISIBILITY, store.getAccess());
313:
314: Element doclet = document.createElement("doclet"); //$NON-NLS-1$
315: xmlJavadocDesc.appendChild(doclet);
316: doclet.setAttribute(store.NAME, store.getDocletName());
317: doclet.setAttribute(store.PATH, store.getDocletPath());
318:
319: String str = store.getOverview();
320: if (str.length() > 0)
321: xmlJavadocDesc.setAttribute(store.OVERVIEW, str);
322:
323: str = store.getAdditionalParams();
324: if (str.length() > 0)
325: xmlJavadocDesc.setAttribute(store.EXTRAOPTIONS, str);
326:
327: }
328:
329: private String toSeparatedList(List packages) {
330: StringBuffer buf = new StringBuffer();
331: Iterator iter = packages.iterator();
332: int nAdded = 0;
333: while (iter.hasNext()) {
334: if (nAdded > 0) {
335: buf.append(',');
336: }
337: nAdded++;
338: String curr = (String) iter.next();
339: buf.append(curr);
340: }
341: return buf.toString();
342: }
343:
344: private String booleanToString(boolean bool) {
345: if (bool)
346: return "true"; //$NON-NLS-1$
347: else
348: return "false"; //$NON-NLS-1$
349: }
350:
351: }
|