/*
* Copyright 2010 t_yano.
*
* Licensed 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.
* under the License.
*/
package jp.javelindev.wicket.parameter;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.Messager;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
import javax.tools.FileObject;
import javax.tools.StandardLocation;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import jp.javelindev.wicket.parameter.annotation.Path;
import jp.javelindev.wicket.parameter.bind.MountPath;
import jp.javelindev.wicket.parameter.bind.MountPoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author t_yano
*/
@SupportedSourceVersion(SourceVersion.RELEASE_6)
@SupportedAnnotationTypes("jp.javelindev.wicket.parameter.annotation.Path")
public class PathAnnotationProcessor extends AbstractProcessor {
private static final Logger LOGGER = LoggerFactory.getLogger(PathAnnotationProcessor.class);
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
if (annotations.isEmpty()) {
return true;
}
Messager messager = processingEnv.getMessager();
messager.printMessage(Diagnostic.Kind.NOTE, "PathAnnotationProcessor now in processing.");
try {
List<PathInfo> pathList = new ArrayList<PathInfo>(annotations.size());
List<Element> elementList = new ArrayList<Element>();
for (TypeElement type : annotations) {
Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(type);
for (Element target : elements) {
Path ann = target.getAnnotation(Path.class);
if (target.getKind().isClass()) {
TypeElement targetAsTypeElement = (TypeElement) target;
pathList.add(new PathInfo(ann, targetAsTypeElement.getQualifiedName().toString()));
elementList.add(target);
}
}
}
Filer filer = processingEnv.getFiler();
JAXBContext context = JAXBContext.newInstance(MountPoint.class);
MountPoint mountPoint = readExistingData(filer, context);
FileObject file = createXmlFile(filer, messager, elementList);
setupMountPoint(mountPoint, pathList);
writeMountPoint(context, file, mountPoint);
} catch (JAXBException ex) {
messager.printMessage(Diagnostic.Kind.ERROR, "Can not create a java source file");
LOGGER.error("Can not create a java source file", ex);
} catch (IOException ex) {
messager.printMessage(Diagnostic.Kind.ERROR, "Can not create a java source file");
LOGGER.error("Can not create a java source file", ex);
}
return true;
}
private void writeMountPoint(JAXBContext context, FileObject xmlFile, MountPoint mountPoint) throws JAXBException, IOException {
BufferedOutputStream output = null;
Marshaller marshaller = context.createMarshaller();
try {
output = new BufferedOutputStream(xmlFile.openOutputStream());
marshaller.marshal(mountPoint, output);
output.flush();
} finally {
if(output != null) {
try {
output.close();
} catch(IOException ex) {
LOGGER.error("Can not close a file.", ex);
}
}
}
}
public static final String XML_FILE_NAME = "META-INF/mountpath/MountPoints.xml";
private MountPoint readExistingData(Filer filer, JAXBContext context) throws IOException, JAXBException {
FileObject file = filer.getResource(StandardLocation.CLASS_OUTPUT, "", XML_FILE_NAME);
InputStream stream = null;
MountPoint mountPoint = null;
try {
stream = new BufferedInputStream(file.openInputStream());
Unmarshaller unmarshaller = context.createUnmarshaller();
LOGGER.info("XML file exists.");
Object unmarshalled = unmarshaller.unmarshal(stream);
if (unmarshalled != null) {
if ((unmarshalled instanceof MountPoint) == false) {
throw new IllegalArgumentException("Unmarshalled Object is not an instance of MountPoint.");
}
mountPoint = (MountPoint) unmarshalled;
}
} catch(FileNotFoundException ex) {
LOGGER.info("XML file does not exists.");
mountPoint = new MountPoint();
} finally {
if (stream != null) {
try {
stream.close();
} catch (IOException ex) {
LOGGER.error("Can not close a file.", ex);
}
}
}
if(mountPoint == null) mountPoint = new MountPoint();
return mountPoint;
}
private FileObject createXmlFile(Filer filer, Messager messager, Collection<? extends Element> annotations) throws IOException {
FileObject file = filer.createResource(
StandardLocation.CLASS_OUTPUT,
"",
XML_FILE_NAME,
annotations.toArray(new Element[0]));
return file;
}
private void setupMountPoint(MountPoint mountPoint, Collection<? extends PathInfo> paths) {
for (PathInfo info : paths) {
Path path = info.path;
MountPath mountPath = new MountPath(info.pageClassName, path.value(), path.isHybrid());
mountPoint.addPath(mountPath);
}
}
private static final class PathInfo {
public final Path path;
public final String pageClassName;
public PathInfo(Path path, String pageClassName) {
this.path = path;
this.pageClassName = pageClassName;
}
}
}