2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Copyright (C) 2017 Amdocs
8 * =============================================================================
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
21 * ECOMP is a trademark and service mark of AT&T Intellectual Property.
22 * ============LICENSE_END=========================================================
25 package org.onap.appc.tools.generator.extensions;
27 import com.google.common.base.Optional;
28 import org.onap.appc.tools.generator.api.ContextBuilder;
29 import org.opendaylight.yangtools.yang.model.api.Module;
30 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
31 import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException;
32 import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceException;
33 import org.opendaylight.yangtools.yang.parser.repo.YangTextSchemaContextResolver;
35 import java.io.IOException;
36 import java.lang.reflect.Modifier;
37 import java.lang.reflect.Proxy;
39 import java.util.Arrays;
40 import java.util.HashMap;
41 import java.util.HashSet;
45 public class YangContextBuilderImpl implements ContextBuilder {
48 public Map<String, Object> buildContext(URL sourceYangURL, String contextConf) throws IOException {
51 Optional<SchemaContext> sc = null;
52 try ( YangTextSchemaContextResolver yangContextResolver =
53 YangTextSchemaContextResolver.create("yang-context-resolver")) {
54 yangContextResolver.registerSource(sourceYangURL);
55 sc = yangContextResolver.getSchemaContext();
56 } catch (SchemaSourceException | IOException | YangSyntaxErrorException e) {
57 throw new IOException(String.format("Exception occurred while processing sourceFileName %s ",sourceYangURL),e);
60 Map<String, Object> map = new HashMap<>();
61 if ( null != sc && sc.isPresent()) {
62 Set<Module> modules = sc.get().getModules();
63 for (final Module module : modules) {
65 Module proxyModule = (new PackagePrivateReflectBug()).buildProxyObjects(module);
66 map.put("module", proxyModule);
75 * The Wrap Proxy uses java Proxy to work around bug JDK-8193172. The Issue is that if a super class is package
76 * private its public methods cause IllegalAccessException when using java reflect to access those methods from a
77 * subclass which is package public.
80 * Caused by: java.lang.IllegalAccessException: Class freemarker.ext.beans.BeansWrapper cannot access a
81 * member of class org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.AbstractEffectiveModule
82 * with modifiers "public final"
84 private static class PackagePrivateReflectBug {
87 * Recursive method that traverses the yang model and wraps objects that extend package private classes
88 * with java proxy objects.
93 private <T> T buildProxyObjects(Object candidateObj) {
95 //can't proxy null so just return
96 if (candidateObj == null) {
101 Class<?> candidateClass = candidateObj.getClass();
103 //prevent a recursive proxy
104 if (Proxy.isProxyClass(candidateClass)) {
105 return (T) candidateObj;
108 //Can�t create a proxy an Array, so replace each
109 //element the array with a proxy if needed.
110 if (candidateClass.isArray()) {
111 Object[] sourceArray = (Object[]) candidateObj;
112 for (int i = 0; i < sourceArray.length; i++) {
113 sourceArray[i] = buildProxyObjects(sourceArray[i]);
115 return (T) candidateObj;
118 //Evaluate if this class must be wrapped in a proxy or not.
119 if (!isCandidateForProxy(candidateClass)) {
120 return (T) candidateObj;
123 //Collect the interfaces for the proxy. Proxy only work with classes
124 //that implement interfaces if there are none the obj cannot be wrapped
126 HashSet<Class<?>> interfaceSet = new HashSet<>();
127 collectInterfaces(candidateClass, interfaceSet);
128 if (interfaceSet.isEmpty()) {
129 return (T) candidateObj;
131 Class<?>[] interfaces = new Class<?>[interfaceSet.size()];
132 interfaceSet.toArray(interfaces);
134 //wrap the Object in a proxy
135 return (T) Proxy.newProxyInstance(
136 candidateClass.getClassLoader(),
138 (proxy, method, args) -> {
139 Object returnObj = method.invoke(candidateObj, args);
140 returnObj = buildProxyObjects(returnObj);
148 * This method determines if the specified class is a candidate for proxy.
151 * @return true - if the specifed class is a Candidate.
153 private boolean isCandidateForProxy(Class<?> fromClass) {
156 Class<?>[] includeClasses = {
157 java.util.Collection.class,
159 org.opendaylight.yangtools.yang.model.api.Module.class
163 for (Class<?> toClass : includeClasses) {
164 if (toClass.isAssignableFrom(fromClass)) {
169 if (isExtendsPackagePrivateSuperClass(fromClass)) {
177 * Test if any of the super packages are package private.
182 private boolean isExtendsPackagePrivateSuperClass(Class<?> clazz) {
183 if (Object.class.equals(clazz)) {
187 int classModifiers = clazz.getModifiers();
188 if (Modifier.isPublic(classModifiers)) {
189 return isExtendsPackagePrivateSuperClass(clazz.getSuperclass());
196 * Collect all of the interfaces this class can be cast too. Tavers the class hierarchy to include interfaces
197 * from the super classes.
202 private void collectInterfaces(Class<?> clazz, Set<Class<?>> classSet) {
203 Class<?>[] interfaces = clazz.getInterfaces();
204 classSet.addAll(Arrays.asList(interfaces));
205 Class<?> superClass = clazz.getSuperclass();
208 if (!Object.class.equals(superClass)) {
209 collectInterfaces(superClass, classSet);