org.netbeans.modules.javahelp.HelpSetRegistrationProcessor Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.modules.javahelp;
import com.sun.java.help.search.Indexer;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic.Kind;
import javax.tools.FileObject;
import javax.tools.StandardLocation;
import org.netbeans.api.javahelp.HelpSetRegistration;
import org.openide.filesystems.FileUtil;
import org.openide.filesystems.annotations.LayerBuilder;
import org.openide.filesystems.annotations.LayerGeneratingProcessor;
import org.openide.filesystems.annotations.LayerGenerationException;
import org.openide.util.Utilities;
import org.openide.util.lookup.ServiceProvider;
import org.openide.xml.XMLUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
@ServiceProvider(service=Processor.class)
@SupportedSourceVersion(SourceVersion.RELEASE_7)
public class HelpSetRegistrationProcessor extends LayerGeneratingProcessor {
public @Override Set getSupportedAnnotationTypes() {
return Collections.singleton(HelpSetRegistration.class.getCanonicalName());
}
protected @Override boolean handleProcess(Set extends TypeElement> annotations, RoundEnvironment roundEnv) throws LayerGenerationException {
if (roundEnv.processingOver()) {
return false;
}
for (javax.lang.model.element.Element e : roundEnv.getElementsAnnotatedWith(HelpSetRegistration.class)) {
HelpSetRegistration r = e.getAnnotation(HelpSetRegistration.class);
String pkg = ((PackageElement) e).getQualifiedName().toString();
String hs = pkg.replace('.', '/') + '/' + r.helpSet();
LayerBuilder builder = layer(e);
builder.file("Services/JavaHelp/" + pkg.replace('.', '-') + ".xml").contents(""
+ "\n"
+ "\n"
+ " \n"
).position(r.position()).write();
Document doc;
URI loc;
try {
loc = builder.validateResource(hs, e, r, "helpSet", false).toUri();
if (loc.getScheme() == null) {
// JDK #6419926: FileObject.toUri() generates URI without schema
loc = Utilities.toURI(new File(loc.toString()));
}
doc = XMLUtil.parse(new InputSource(loc.toString()), true, false, XMLUtil.defaultErrorHandler(), new EntityResolver() {
public @Override InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
if (publicId.equals("-//Sun Microsystems Inc.//DTD JavaHelp HelpSet Version 1.0//EN")) {
return new InputSource(HelpSetRegistrationProcessor.class.getResource("resources/helpset_1_0.dtd").toString());
} else if (publicId.equals("-//Sun Microsystems Inc.//DTD JavaHelp HelpSet Version 2.0//EN")) {
return new InputSource(HelpSetRegistrationProcessor.class.getResource("resources/helpset_2_0.dtd").toString());
} else {
return null;
}
}
});
} catch (IOException x) {
throw new LayerGenerationException("Could not parse " + hs + ": " + x, e, processingEnv, r, "helpSet");
} catch (SAXException x) {
throw new LayerGenerationException("Could not parse " + hs + ": " + x, e, processingEnv, r, "helpSet");
}
String searchDir = null;
for (Element view : XMLUtil.findSubElements(doc.getDocumentElement())) {
if (!view.getTagName().equals("view")) {
continue;
}
Element type = XMLUtil.findElement(view, "type", null);
if ("javax.help.SearchView".equals(XMLUtil.findText(type))) {
Element data = XMLUtil.findElement(view, "data", null);
if (data.getAttribute("engine").equals("com.sun.java.help.search.DefaultSearchEngine")) {
searchDir = XMLUtil.findText(data)/* XXX better to set XML parser to ignore ws */.trim();
break;
}
}
}
if (searchDir != null) {
if ("file".equals(loc.getScheme())) {
File d = Utilities.toFile(loc).getParentFile();
String out = hs.replaceFirst("/[^/]+$", "/") + searchDir + "/";
try {
File config = File.createTempFile("jhindexer-config", ".txt");
try {
AtomicInteger cnt = new AtomicInteger();
OutputStream os = new FileOutputStream(config);
try {
PrintWriter pw = new PrintWriter(os);
pw.println("IndexRemove " + d + File.separator);
scan(d, pw, cnt, new HashSet(Arrays.asList(r.excludes())), "");
pw.flush();
} finally {
os.close();
}
processingEnv.getMessager().printMessage(Kind.NOTE, "Indexing " + cnt + " HTML files in " + d + " into " + out);
File db = createTempFile("jhindexer-out", "");
db.delete();
db.mkdir();
try {
Indexer.main(new String[] {
"-c", config.getAbsolutePath(),
"-db", db.getAbsolutePath()
});
} finally {
for (File f : db.listFiles()) {
FileObject dest = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", out + f.getName(), e);
os = dest.openOutputStream();
try {
InputStream is = new FileInputStream(f);
try {
FileUtil.copy(is, os);
} finally {
is.close();
}
} finally {
os.close();
}
f.delete();
}
db.delete();
}
} finally {
config.delete();
}
} catch (Exception x) {
processingEnv.getMessager().printMessage(Kind.ERROR, "Could not run indexer: " + x, e);
}
} else {
processingEnv.getMessager().printMessage(Kind.ERROR, "Cannot run indexer on non-local files: " + loc, e);
}
}
// XXX try to port CheckHelpSets
}
return true;
}
/** Create a temp file that can be used for turning into directory
* and setting as database directory for indexing JavaHelp files.
*
* This method was created because default temp directory on some systems
* (Mac) contains plus sign "+" in its path. Plus signs are replaced with
* spaces in JavaHelp indexer because of encoding path to URL and later
* decoding URL back to path.
*
* #201194
*
* This is workaround only. Fixed upstream, see
* http://java.net/jira/browse/JAVAHELP-33.
* When a new version of JavaHelp with that fix is released (e.g. 2.0_06)
* and bundled in NetBeans, standard File.createTempFile can be used instead
* of this method, and createTempFile, replaceTempFile and isUrlCompatible
* methods can be removed.
*/
static File createTempFile(String pref, String suff) throws IOException {
File f = File.createTempFile(pref, suff); //file in default tmp folder
if (!isUrlCompatible(f)) {
if (Utilities.isWindows()) {
f = replaceTempFile(f, "c:\\Temp", pref, suff); //NOI18N
} else if (Utilities.isUnix()) {
f = replaceTempFile(f, "/tmp", pref, suff); //NOI18N
}
}
return f;
}
/** Try to replace invalid temp file with a better one.
* On success, original temp file is deleted and newly found one is
* returned. Otherwise, original temp file is returned.
*/
private static File replaceTempFile(File origTmpFile, String tmpDirPath,
String pref, String suff) {
File tmpDir = new File(tmpDirPath);
if (tmpDir.isDirectory()) {
File tmpFile;
int num = 0;
do {
String fileName = pref + System.currentTimeMillis()
+ "_" + (++num) + suff; //NOI18N
tmpFile = new File(tmpDir, fileName);
} while (tmpFile.exists()); // file to create cannot already exist
try {
tmpFile.createNewFile();
} catch (Exception e) {
return origTmpFile;
}
if (tmpFile.isFile() && isUrlCompatible(tmpFile)) {
origTmpFile.delete();
return tmpFile;
} else {
tmpFile.delete();
return origTmpFile;
}
} else {
return origTmpFile;
}
}
/** Test that file path is preserved if it is encoded to to URL and
* decoded back to path.
*
* This happens internally in the JavaHelp Indexer and it can damage paths
* that contain special characters (e.g. plus sign "+").
*/
static boolean isUrlCompatible(File f) {
URL baseURL;
try {
baseURL = new URL("file", "", f.getAbsolutePath()); //NOI18N
} catch (MalformedURLException ex) {
return false;
}
String fileFromUrl = baseURL.getFile();
String decodedFileFromUrl = URLDecoder.decode(fileFromUrl);
return f.getAbsolutePath().equals(decodedFileFromUrl);
}
private static void scan(File d, PrintWriter pw, AtomicInteger cnt, Set excludes, String path) {
for (File f : d.listFiles()) {
String name = f.getName();
if (f.isDirectory()) {
scan(f, pw, cnt, excludes, path + name + '/');
} else if (!excludes.contains(path + name) && name.matches(".+[.]html?$")) {
pw.println("File " + f);
cnt.incrementAndGet();
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy