/** * Get more info at : www.jrebirth.org . * Copyright JRebirth.org © 2011-2015 * Contact : sebastien.bordes@jrebirth.org * * 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. */ package org.jrebirth.af.processor; import java.io.File; import java.io.FileInputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedSourceVersion; import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; import javax.lang.model.element.TypeElement; import javax.lang.model.type.DeclaredType; import javax.lang.model.type.MirroredTypeException; import javax.lang.model.type.TypeMirror; import javax.lang.model.util.Elements; import javax.tools.Diagnostic.Kind; import javax.tools.FileObject; import javax.tools.StandardLocation; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBElement; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import javax.xml.bind.Unmarshaller; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamReader; import org.jrebirth.af.modular.model.Component; import org.jrebirth.af.modular.model.Module; import org.jrebirth.af.modular.model.ObjectFactory; import org.jrebirth.af.modular.model.Registration; import org.jrebirth.af.modular.model.RegistrationEntry; import org.jrebirth.af.processor.annotation.Register; import org.jrebirth.af.processor.annotation.RegistrationPoint; import org.jrebirth.af.processor.annotation.WarmUp; /** * The Class ComponentProcessor. */ @SupportedSourceVersion(SourceVersion.RELEASE_8) public class ComponentProcessor extends AbstractProcessor { /** The module config path. */ private static String MODULE_CONFIG_PATH = "JRAF-INF"; /** The module config file name. */ private static String MODULE_CONFIG_FILE_NAME = "module.xml"; /** The factory. */ private ObjectFactory factory; /** The jaxb context. */ private JAXBContext jaxbContext; /** * {@inheritDoc} */ @Override public synchronized void init(final ProcessingEnvironment processingEnv) { super.init(processingEnv); this.factory = new ObjectFactory(); try { this.jaxbContext = JAXBContext.newInstance("org.jrebirth.af.modular.model", ObjectFactory.class.getClassLoader()); // NOSONAR } catch (final JAXBException e) { e.printStackTrace(); } } /** * {@inheritDoc} */ @Override public Set<String> getSupportedAnnotationTypes() { return new HashSet<>(Arrays.asList(Register.class.getName(), RegistrationPoint.class.getName())); } /** * {@inheritDoc} */ @Override public boolean process(final Set<? extends TypeElement> annotations, final RoundEnvironment roundEnv) { if (roundEnv.processingOver()) { return false; } final Map<String, Set<String>> services = new HashMap<String, Set<String>>(); final Elements elements = this.processingEnv.getElementUtils(); final Set<? extends Element> warmUps = roundEnv.getElementsAnnotatedWith(WarmUp.class); final Set<? extends Element> registrationPoints = roundEnv.getElementsAnnotatedWith(RegistrationPoint.class); final Set<? extends Element> registrations = roundEnv.getElementsAnnotatedWith(Register.class); // Load Module module = null;// loadModuleFile(); if (module == null) { module = createModule(); } for (final Element element : warmUps) { final WarmUp warmUp = element.getAnnotation(WarmUp.class); // Only managed Component if (warmUp != null /* && element.getKind().getClass().isAssignableFrom(AbstractComponent.class) */) { final Component c = this.factory.createComponent(); c.setClazz(getClassName(element)); module.getWarmUp().getComponent().add(c); // processingEnv.getMessager().printMessage(Kind.MANDATORY_WARNING, r.toString(), element); } } // for (final Element element : registrationPoints) { final RegistrationPoint registrationPoint = element.getAnnotation(RegistrationPoint.class); // Only managed annotated interfaces if (registrationPoint != null && element.getKind().isInterface()) { final Registration r = this.factory.createRegistration(); r.setClazz(getClassName(element)); r.setExclusive(registrationPoint.exclusive()); module.getRegistrations().getRegistration().add(r); // processingEnv.getMessager().printMessage(Kind.MANDATORY_WARNING, r.toString(), element); } } for (final Element element : registrations) { final Register registration = element.getAnnotation(Register.class); // Only managed annotated concrete classes if (registration != null && !element.getKind().isInterface() && element.getKind().isClass()) { final RegistrationEntry re = this.factory.createRegistrationEntry(); re.setClazz(getClassName(element)); re.setPriority(registration.priority().name()); String registeredClass; TypeMirror value = null; try { registration.value(); } catch (final MirroredTypeException mte) { value = mte.getTypeMirror(); } registeredClass = getClassName(value); for (final Registration r : module.getRegistrations().getRegistration()) { if (registeredClass != null && registeredClass.equals(r.getClazz())) { if (r.getRegistrationEntries() == null) { r.setRegistrationEntries(this.factory.createRegistrationEntryList()); } r.getRegistrationEntries().getRegistrationEntry().add(re); } } // processingEnv.getMessager().printMessage(Kind.MANDATORY_WARNING, re.toString(), element); } } // // also load up any existing values, since this compilation may be partial // Filer filer = processingEnv.getFiler(); // for (Map.Entry<String, Set<String>> e : services.entrySet()) { // // Registration r = factory.createRegistration(); // r.setClazz(e.getValue().toString()); // // if (module.getRegistrations() == null) { // module.setRegistrations(factory.createRegistrationList()); // } // module.getRegistrations().getRegistration().add(r); // // } saveModule(module); return true; } /** * Save module. * * @param module the module */ private void saveModule(final Module module) { final OutputStreamWriter out; try { final FileObject fileObject = this.processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", MODULE_CONFIG_PATH + "/" + MODULE_CONFIG_FILE_NAME); // final File path = new File(MODULE_CONFIG_PATH); // path.mkdirs(); // out = new OutputStreamWriter(new FileOutputStream(MODULE_CONFIG_PATH + "/" + MODULE_CONFIG_FILE_NAME), Charset.forName("UTF-8")); // final XMLStreamWriter xmlStreamWriter = XMLOutputFactory.newInstance().createXMLStreamWriter(out); final Marshaller marshaller = this.jaxbContext.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); // // marshaller.marshal(factory.createModule(module), xmlStreamWriter); // OutputStream os = new FileOutputStream(MODULE_CONFIG_PATH + "/" + MODULE_CONFIG_FILE_NAME); // XMLOutputFactory outputFactory = XMLOutputFactory.newInstance(); // XMLStreamWriter writer = outputFactory.createXMLStreamWriter(os); marshaller.marshal(this.factory.createModule(module), fileObject.openOutputStream()); marshaller.marshal(this.factory.createModule(module), System.out); // os.close(); } catch (final Exception e) { e.printStackTrace(); } } /** * Creates the module. * * @return the module */ private Module createModule() { final Module module = this.factory.createModule(); module.setWarmUp(this.factory.createWarmUpList()); module.setRegistrations(this.factory.createRegistrationList()); // return module; } /** * Load module file. * * @return the module */ private Module loadModuleFile() { Module module = null; final File f = new File(MODULE_CONFIG_PATH + "/" + MODULE_CONFIG_FILE_NAME); if (f.exists()) { try { final Unmarshaller unmarshaller = this.jaxbContext.createUnmarshaller(); final InputStreamReader in = new InputStreamReader(new FileInputStream(f));// InputStreamReader(Thread.currentThread().getContextClassLoader().getResourceAsStream(MODULE_CONFIG_PATH + // "/" + MODULE_CONFIG_FILE_NAME), Charset.forName("UTF-8")); final XMLStreamReader xsr = XMLInputFactory.newInstance().createXMLStreamReader(in); final Object o = unmarshaller.unmarshal(xsr); module = Module.class.cast(JAXBElement.class.cast(o).getValue()); } catch (final Exception e) { e.printStackTrace(); } } return module; } /** * Gets the class name. * * @param element the element * @return the class name */ private String getClassName(final Element element) { return getClassName(element.asType()); } /** * Gets the class name. * * @param t the t * @return the class name */ private String getClassName(final TypeMirror t) { String res = null; if (t instanceof DeclaredType) { final DeclaredType dt = (DeclaredType) t; res = ((TypeElement) dt.asElement()).getQualifiedName().toString(); } return res; } /** * Error. * * @param source the source * @param msg the msg */ private void error(final Element source, final String msg) { this.processingEnv.getMessager().printMessage(Kind.ERROR, msg, source); } // private TypeElement getContract(TypeElement type, Register a) { // // explicitly specified? // try { // a.value(); // throw new AssertionError(); // } catch (MirroredTypeException e) { // TypeMirror m = e.getTypeMirror(); // if (m.getKind() == TypeKind.VOID) { // // contract inferred from the signature // boolean hasBaseClass = type.getSuperclass().getKind() != TypeKind.NONE && !isObject(type.getSuperclass()); // boolean hasInterfaces = !type.getInterfaces().isEmpty(); // if (hasBaseClass ^ hasInterfaces) { // if (hasBaseClass) // return (TypeElement) ((DeclaredType) type.getSuperclass()).asElement(); // return (TypeElement) ((DeclaredType) type.getInterfaces().get(0)).asElement(); // } // // error(type, "Contract type was not specified, but it couldn't be inferred."); // return null; // } // // if (m instanceof DeclaredType) { // DeclaredType dt = (DeclaredType) m; // return (TypeElement) dt.asElement(); // } else { // error(type, "Invalid type specified as the contract"); // return null; // } // } // // } // // now write them back out // for (Map.Entry<String, Set<String>> e : services.entrySet()) { // try { // processingEnv.getMessager().printMessage(Kind.NOTE, "Writing JRAF-INF/registration.jraf"); // FileObject f = filer.createResource(StandardLocation.CLASS_OUTPUT, "", "JRAF-INF/registration.jraf"); // PrintWriter pw = new PrintWriter(new OutputStreamWriter(f.openOutputStream(), "UTF-8")); // for (String value : e.getValue()) // pw.println(value); // pw.close(); // } catch (IOException x) { // processingEnv.getMessager().printMessage(Kind.ERROR, "Failed to write service definition files: " + x); // } // } // ClassPool pool = ClassPool.getDefault(); // CtClass cc; // try { // //cc = pool.get(elements.getBinaryName(type).toString()); // cc = pool.getCtClass(elements.getBinaryName(type).toString()); // CtField f = new CtField(CtClass.intType, "hiddenValue", cc); // f.setModifiers(java.lang.reflect.Modifier.PUBLIC); // cc.addField(f); // // cc.writeFile(); // // } catch (NotFoundException e1) { // // TODO Auto-generated catch block // e1.printStackTrace(); // } catch (CannotCompileException e1) { // // TODO Auto-generated catch block // e1.printStackTrace(); // } catch (IOException e1) { // // TODO Auto-generated catch block // e1.printStackTrace(); // } }