Package org.jvnet.hk2.config

Source Code of org.jvnet.hk2.config.ConfiguredScanner

/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2007-2011 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License").  You
* may not use this file except in compliance with the License.  You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt.  See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license."  If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above.  However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package org.jvnet.hk2.config;
import com.sun.hk2.component.Holder;
import com.sun.hk2.component.IntrospectionScanner;
import com.sun.hk2.component.LazyInhabitant;
import org.glassfish.hk2.classmodel.reflect.*;
import org.jvnet.hk2.annotations.Inject;
import org.jvnet.hk2.annotations.Service;
import org.jvnet.hk2.component.Habitat;
import org.jvnet.hk2.component.MultiMap;

import java.util.HashSet;
import java.util.Set;
import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* Scanner for @Configured annotated classes
*
* @author Jerome Dochez
*/
@Service
public class ConfiguredScanner implements IntrospectionScanner {

    @Inject
    Habitat habitat;

    ParsingContext context;


    @Override
    public void parse(ParsingContext context, Holder<ClassLoader> loader) {

        this.context = context;
        AnnotationType configured = (AnnotationType) context.getTypes().getBy(Configured.class.getName());
        if (configured==null) return;

        for (AnnotatedElement ae : configured.allAnnotatedTypes()) {
            if (!(ae instanceof ExtensibleType)) {
                continue;
            }
            MultiMap<String,String> metadata = new MultiMap<String,String>();
            parse((ExtensibleType<?>) ae, metadata);

            AnnotationModel c = ae.getAnnotation(Configured.class.getName());
            String elementName = (String) c.getValues().get("value");
            if(elementName==null || elementName.length()==0) { // infer default
                elementName = Dom.convertName(ae.getName().substring(ae.getName().lastIndexOf('.')+1));
            }

            metadata.add(ConfigMetadata.TARGET, ae.getName());

            // register the injector.
            LazyInhabitant inhabitant = new LazyInhabitant(habitat, loader, NoopConfigInjector.class.getName(), metadata);
            habitat.addIndex(inhabitant, InjectionTarget.class.getName(), ae.getName());
            habitat.addIndex(inhabitant, ConfigInjector.class.getName(), elementName);
        }
    }

    private void parse(ExtensibleType<?> type, MultiMap<String, String> metadata) {
        Stack<ExtensibleType<?>> q = new Stack<ExtensibleType<?>>();
        Set<Type> visited = new HashSet<Type>();
        q.push(type);

        while (!q.isEmpty()) {
            ExtensibleType<?> t = q.pop();
            if (!visited.add(t)) continue;   // been here already

            if (t instanceof ClassModel) {
                for (FieldModel f : ((ClassModel) t).getFields())
                    generate(f);
            }

            for (MethodModel m : t.getMethods())
                generate(m, metadata);

            for (ExtensibleType<?> child : t.getInterfaces())
                q.add(child);

            if (t.getParent()!=null)
                q.add(t.getParent());
        }
    }

    private void generate(FieldModel f) {
        throw new RuntimeException("Not implemented");
    }

    private void generate(MethodModel m, MultiMap<String, String> metadata) {
        AnnotationModel attribute = m.getAnnotation(Attribute.class.getName());
        AnnotationModel element = m.getAnnotation(Element.class.getName());

        if (attribute != null) {
            generateAttribute(attribute, m, metadata);
            if (element != null)
                throw new RuntimeException("Cannot have both @Element and @Attribute at the same time on method " + m.getName());
        } else {
            if (element != null)
                generateElement(element, m, metadata);
        }
    }

    private void generateAttribute(AnnotationModel attribute, MethodModel m, MultiMap<String, String> metadata) {
        String name = Dom.convertName(m.getName());
        String xmlTokenName = '@' + name;
        boolean isRequired = Boolean.parseBoolean((String) attribute.getValues().get("isRequired"));
        metadata.add(xmlTokenName,isRequired?"required":"optional");
        String defaultValue = (String) attribute.getValues().get("defaultValue");
        if (defaultValue!=null && !defaultValue.isEmpty()) {
            if (defaultValue.indexOf(',')!=-1) {
                metadata.add(xmlTokenName, '"' + "default:" + defaultValue + '"');
            } else {
                metadata.add(xmlTokenName, "default:" + defaultValue);                       
            }
        }
        String signature = m.getSignature();
        String[] arguments = m.getArgumentTypes();
        String refTypeAsString;
        if (arguments.length==0) {
            refTypeAsString = m.getReturnType();
        } else {
            if (arguments.length!=1) {
                throw new RuntimeException("@Attribute method cannot have more than 1 argument " + m.getSignature());
            }
            refTypeAsString = arguments[0];
        }
        // we need to handle collection types
        boolean isCollection = refTypeAsString.startsWith("java.util.List<L");
        if (isCollection) {
            refTypeAsString = refTypeAsString.substring("java.util.List<L".length());
        }
        metadata.add(xmlTokenName, "datatype:" + refTypeAsString);
        Type refType = context.getTypes().getBy(refTypeAsString);
        Boolean isReference = (Boolean) attribute.getValues().get("reference");
        if (refType==null || (isReference!=null &&isReference)) {
            // leaf
            metadata.add(xmlTokenName, makeCollectionIfNecessary(isCollection, "leaf"));
            if (isReference!=null && isReference) {
                metadata.add(xmlTokenName, "reference");
            }
        } else {
            // node
            metadata.add(xmlTokenName, makeCollectionIfNecessary(isCollection, refTypeAsString));
        }
        Boolean isKey = (Boolean) attribute.getValues().get("key");
        if (isKey!=null && isKey) {
            metadata.add(ConfigMetadata.KEY, xmlTokenName);
            metadata.add(ConfigMetadata.KEYED_AS,m.getDeclaringType().getName());
        }
    }

    private String makeCollectionIfNecessary(boolean isCollection, String value) {
        if (isCollection) {
            return "collection:" + value;
        } else {
            return value;
        }
    }

    private void generateElement(AnnotationModel element, MethodModel m, MultiMap<String, String> metadata) {
        String name = Dom.convertName(m.getName());
        String xmlTokenName = "<" + name + ">";
        String[] arguments = m.getArgumentTypes();
        String refTypeAsString;
        if (arguments.length==0) {
            refTypeAsString = m.getReturnType();
        } else {
            if (arguments.length!=1) {
                throw new RuntimeException("@Element method cannot have more than 1 argument " + m.getSignature());
            }
            refTypeAsString = arguments[0];
        }
        boolean isCollection = refTypeAsString.startsWith("java.util.List<L");
        if (isCollection) {
            refTypeAsString = refTypeAsString.substring("java.util.List<L".length());
        }
        Boolean isReference = (Boolean) element.getValues().get("reference");
        Type refType = context.getTypes().getBy(refTypeAsString);
        if (refType==null || (isReference!=null && isReference)) {
            // leaf
            metadata.add(xmlTokenName, makeCollectionIfNecessary(isCollection, "leaf"));
            if (isReference!=null && isReference) {
                metadata.add(xmlTokenName, "reference");
            }
        } else {
            // node
            metadata.add(xmlTokenName, makeCollectionIfNecessary(isCollection, refTypeAsString));
        }
    }

}
TOP

Related Classes of org.jvnet.hk2.config.ConfiguredScanner

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.