1/*
2 * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package com.sun.tools.internal.ws.processor.modeler.annotation;
27
28import javax.annotation.processing.ProcessingEnvironment;
29import javax.lang.model.element.ElementKind;
30import javax.lang.model.element.ExecutableElement;
31import javax.lang.model.element.TypeElement;
32import javax.lang.model.element.VariableElement;
33import javax.lang.model.type.DeclaredType;
34import javax.lang.model.type.TypeKind;
35import javax.lang.model.type.TypeMirror;
36import javax.lang.model.util.ElementFilter;
37import java.util.Collection;
38import javax.lang.model.element.Element;
39
40/**
41 * @author WS Development Team
42 */
43final class TypeModeler {
44
45    private static final String REMOTE = "java.rmi.Remote";
46    private static final String REMOTE_EXCEPTION = "java.rmi.RemoteException";
47
48    private TypeModeler() {
49    }
50
51    public static TypeElement getDeclaration(TypeMirror typeMirror) {
52        if (typeMirror != null && typeMirror.getKind().equals(TypeKind.DECLARED))
53            return (TypeElement) ((DeclaredType) typeMirror).asElement();
54        return null;
55    }
56
57    public static TypeElement getDeclaringClassMethod(TypeMirror theClass, String methodName, TypeMirror[] args) {
58        return getDeclaringClassMethod(getDeclaration(theClass), methodName, args);
59    }
60
61    public static TypeElement getDeclaringClassMethod(TypeElement theClass, String methodName, TypeMirror[] args) {
62
63        TypeElement retClass = null;
64        if (theClass.getKind().equals(ElementKind.CLASS)) {
65            TypeMirror superClass = theClass.getSuperclass();
66            if (!superClass.getKind().equals(TypeKind.NONE))
67                retClass = getDeclaringClassMethod(superClass, methodName, args);
68        }
69        if (retClass == null) {
70            for (TypeMirror interfaceType : theClass.getInterfaces()) {
71                retClass = getDeclaringClassMethod(interfaceType, methodName, args);
72            }
73        }
74        if (retClass == null) {
75            Collection<? extends ExecutableElement> methods = ElementFilter.methodsIn(theClass.getEnclosedElements());
76            for (ExecutableElement method : methods) {
77                if (method.getSimpleName().toString().equals(methodName)) {
78                    retClass = theClass;
79                    break;
80                }
81            }
82        }
83        return retClass;
84    }
85
86    public static Collection<DeclaredType> collectInterfaces(TypeElement type) {
87        @SuppressWarnings({"unchecked"})
88        Collection<DeclaredType> interfaces = (Collection<DeclaredType>) type.getInterfaces();
89        for (TypeMirror interfaceType : type.getInterfaces()) {
90            interfaces.addAll(collectInterfaces(getDeclaration(interfaceType)));
91        }
92        return interfaces;
93    }
94
95    public static boolean isSubclass(String subTypeName, String superTypeName, ProcessingEnvironment env) {
96        return isSubclass(env.getElementUtils().getTypeElement(subTypeName), env.getElementUtils().getTypeElement(superTypeName), env);
97    }
98
99    public static boolean isSubclass(TypeElement subType, TypeElement superType, ProcessingEnvironment env) {
100        return !subType.equals(superType) && isSubElement(subType, superType);
101    }
102
103    public static TypeMirror getHolderValueType(TypeMirror type, TypeElement defHolder, ProcessingEnvironment env) {
104        TypeElement typeElement = getDeclaration(type);
105        if (typeElement == null)
106            return null;
107
108        if (isSubElement(typeElement, defHolder)) {
109            if (type.getKind().equals(TypeKind.DECLARED)) {
110                Collection<? extends TypeMirror> argTypes = ((DeclaredType) type).getTypeArguments();
111                if (argTypes.size() == 1) {
112                    return argTypes.iterator().next();
113                } else if (argTypes.isEmpty()) {
114                    VariableElement member = getValueMember(typeElement);
115                    if (member != null) {
116                        return member.asType();
117                    }
118                }
119            }
120        }
121        return null;
122    }
123
124    public static VariableElement getValueMember(TypeMirror classType) {
125        return getValueMember(getDeclaration(classType));
126    }
127
128    public static VariableElement getValueMember(TypeElement type) {
129        VariableElement member = null;
130        for (VariableElement field : ElementFilter.fieldsIn(type.getEnclosedElements())) {
131            if ("value".equals(field.getSimpleName().toString())) {
132                member = field;
133                break;
134            }
135        }
136        if (member == null && type.getKind().equals(ElementKind.CLASS))
137            member = getValueMember(type.getSuperclass());
138        return member;
139    }
140
141    public static boolean isSubElement(TypeElement d1, TypeElement d2) {
142        if (d1.equals(d2))
143            return true;
144        TypeElement superClassDecl = null;
145        if (d1.getKind().equals(ElementKind.CLASS)) {
146            TypeMirror superClass = d1.getSuperclass();
147            if (!superClass.getKind().equals(TypeKind.NONE)) {
148                superClassDecl = (TypeElement) ((DeclaredType) superClass).asElement();
149                if (superClassDecl.equals(d2))
150                    return true;
151            }
152        }
153        for (TypeMirror superIntf : d1.getInterfaces()) {
154            DeclaredType declaredSuperIntf = (DeclaredType) superIntf;
155            if (declaredSuperIntf.asElement().equals(d2)) {
156                return true;
157            }
158            if (isSubElement((TypeElement) declaredSuperIntf.asElement(), d2)) {
159                return true;
160            } else if (superClassDecl != null && isSubElement(superClassDecl, d2)) {
161                return true;
162            }
163        }
164        return false;
165    }
166
167    public static boolean isRemoteException(ProcessingEnvironment env, TypeMirror typeMirror) {
168        Element element = env.getTypeUtils().asElement(typeMirror);
169        if (element.getKind() == ElementKind.CLASS) {
170            TypeElement te = (TypeElement) element;
171            TypeKind tk = typeMirror.getKind();
172            while (tk != TypeKind.NONE && !te.getQualifiedName().contentEquals(REMOTE_EXCEPTION)) {
173                TypeMirror superType = te.getSuperclass();
174                te = (TypeElement) env.getTypeUtils().asElement(superType);
175                tk = superType.getKind();
176            }
177            return tk != TypeKind.NONE;
178        }
179        return false;
180    }
181
182    public static boolean isRemote(/*@NotNull*/ TypeElement typeElement) {
183        for (TypeMirror superType : typeElement.getInterfaces()) {
184            TypeElement name = (TypeElement) ((DeclaredType) superType).asElement();
185            if (name.getQualifiedName().contentEquals(REMOTE)) {
186                return true;
187            }
188            isRemote(name);
189        }
190        return false;
191    }
192}
193