/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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.apache.felix.schematizer.impl; //import java.lang.annotation.Annotation; //import java.lang.reflect.Field; //import java.lang.reflect.Method; //import java.lang.reflect.Modifier; //import java.lang.reflect.ParameterizedType; //import java.lang.reflect.Type; //import java.util.ArrayList; //import java.util.Arrays; //import java.util.Collection; //import java.util.Collections; //import java.util.Comparator; //import java.util.HashMap; //import java.util.HashSet; //import java.util.LinkedHashMap; //import java.util.List; //import java.util.Map; //import java.util.Map.Entry; //import java.util.Optional; //import java.util.Set; //import java.util.function.Function; //import java.util.stream.Collectors; // //import org.apache.felix.schematizer.Node; //import org.apache.felix.schematizer.Node.CollectionType; //import org.apache.felix.schematizer.Schema; //import org.apache.felix.schematizer.Schematizer; //import org.apache.felix.schematizer.TypeRule; //import org.osgi.dto.DTO; //import org.osgi.framework.Bundle; //import org.osgi.framework.ServiceFactory; //import org.osgi.framework.ServiceRegistration; //import org.osgi.util.converter.StandardConverter; //import org.osgi.util.converter.TypeReference; // //public class SchematizerImplOLD implements Schematizer, ServiceFactory<Schematizer> { // // private final Map<String, SchemaImpl> schemas = new HashMap<>(); // private volatile Map<String, Map<String, Object>> typeRules = new HashMap<>(); // private final List<ClassLoader> classloaders = new ArrayList<>(); // // @Override // public Schematizer getService( Bundle bundle, ServiceRegistration<Schematizer> registration ) { // return this; // } // // @Override // public void ungetService(Bundle bundle, ServiceRegistration<Schematizer> registration, Schematizer service) { // // For now, a brutish, simplistic version. If there is any change to the environment, just // // wipe the state and start over. // // // // TODO: something more precise, which will remove only the classes that are no longer valid (if that is possible). // schemas.clear(); // typeRules.clear(); // classloaders.clear(); // } // // @Override // public Optional<Schema> get(String name) { // if (!schemas.containsKey(name)) { // SchemaImpl schema = schematize(name, ""); // schemas.put(name, schema); // } // // return Optional.ofNullable(schemas.get(name)); // } // // @Override // public Optional<Schema> from(String name, Map<String, Node.DTO> map) { // try { // // TODO: some validation of the Map here would be good // SchemaImpl schema = new SchemaImpl(name); // Object rootMap = map.get("/"); // Node.DTO rootDTO = new StandardConverter().convert(rootMap).to(Node.DTO.class); // Map<String, NodeImpl> allNodes = new HashMap<>(); // NodeImpl root = new NodeImpl(rootDTO, "", new Instantiator(classloaders), allNodes); // associateChildNodes(root); // schema.add(root); // schema.add(allNodes); // return Optional.of(schema); // } catch (Throwable t) { // return Optional.empty(); // } // } // // @Override // public <T extends DTO> Schematizer rule(String name, TypeRule<T> rule) { // Map<String, Object> rules = rulesFor(name); // rules.put(rule.getPath(), rule.getType()); // return this; // } // // @Override // public <T extends DTO> Schematizer rule(String name, String path, TypeReference<T> type) { // Map<String, Object> rules = rulesFor(name); // rules.put(path, type); // return this; // } // // @Override // public <T extends DTO> Schematizer rule(String name, TypeReference<T> type) { // Map<String, Object> rules = rulesFor(name); // rules.put("/", type); // return this; // } // // @Override // public <T> Schematizer rule(String name, String path, Class<T> cls) { // Map<String, Object> rules = rulesFor(name); // rules.put(path, cls); // return this; // } // // private Map<String, Object> rulesFor(String name) { // if (!typeRules.containsKey(name)) // typeRules.put(name, new HashMap<>()); // // return typeRules.get(name); // } // // @Override // public Schematizer usingLookup( ClassLoader classloader ) { // if (classloader != null) // classloaders.add(classloader); // return this; // } // // /** // * Top-level entry point for schematizing a DTO. This is the starting point to set up the // * parsing. All other methods make recursive calls. // */ // private SchemaImpl schematize(String name, String contextPath) { // Map<String, Object> rules = typeRules.get(name); // rules = ( rules != null ) ? rules : Collections.emptyMap(); // return SchematizerImplOLD.internalSchematize(name, contextPath, rules, false, this); // } // // @SuppressWarnings( { "unchecked", "rawtypes" } ) // /** // * Schematize any node, without knowing in advance its type. // */ // private static SchemaImpl internalSchematize( // String name, // String contextPath, // Map<String, Object> rules, // boolean isCollection, // SchematizerImplOLD schematizer) { // Class<?> cls = null; // TypeReference<? extends DTO> ref = null; // if (contextPath.isEmpty() && rules.containsKey("/")) { // ref = (TypeReference)typeReferenceOf(rules.get("/")); // if (ref == null ) // cls = rawClassOf(rules.get("/")); // } // // if (rules.containsKey(contextPath)) { // ref = (TypeReference)(typeReferenceOf(rules.get(contextPath))); // if (ref == null ) // cls = rawClassOf(rules.get(contextPath)); // } // // if (ref != null ) // cls = rawClassOf(ref); // // if (cls == null) // return handleInvalid(); // // if (DTO.class.isAssignableFrom(cls)) { // Class<? extends DTO> targetCls = (Class<DTO>)cls; // return schematizeDTO(name, targetCls, ref, contextPath, rules, isCollection, schematizer); // } // // return schematizeObject( name, cls, contextPath, rules, isCollection, schematizer); // } // // private static SchemaImpl schematizeDTO( // String name, // Class<? extends DTO> targetCls, // TypeReference<? extends DTO> ref, // String contextPath, // Map<String, Object> rules, // boolean isCollection, // SchematizerImplOLD schematizer) { // // SchemaImpl schema = new SchemaImpl(name); // NodeImpl rootNode; // if (ref != null) // rootNode = new NodeImpl(contextPath, ref, false, contextPath + "/"); // else // rootNode = new NodeImpl(contextPath, targetCls, false, contextPath + "/"); // schema.add(rootNode); // Map<String, NodeImpl> m = createMapFromDTO(name, targetCls, ref, contextPath, rules, schematizer); // m.values().stream().filter(v -> v.absolutePath().equals(rootNode.absolutePath() + v.name())).forEach(v -> rootNode.add(v)); // associateChildNodes( rootNode ); // schema.add(m); // return schema; // } // // private static SchemaImpl schematizeObject( // String name, // Class<?> targetCls, // String contextPath, // Map<String, Object> rules, // boolean isCollection, // SchematizerImplOLD schematizer) { // // SchemaImpl schema = new SchemaImpl(name); // NodeImpl node = new NodeImpl(contextPath, targetCls, isCollection, contextPath + "/"); // schema.add(node); // return schema; // } // // private static final Comparator<Entry<String, NodeImpl>> byPath = (e1, e2) -> e1.getValue().absolutePath().compareTo(e2.getValue().absolutePath()); // private static Map<String, NodeImpl> createMapFromDTO( // String name, // Class<?> targetCls, // TypeReference<? extends DTO> ref, // String contextPath, // Map<String, Object> typeRules, // SchematizerImplOLD schematizer) { // Set<String> handledFields = new HashSet<>(); // // Map<String, NodeImpl> result = new HashMap<>(); // for (Field f : targetCls.getDeclaredFields()) { // handleField(name, f, handledFields, result, targetCls, ref, contextPath, typeRules, schematizer); // } // for (Field f : targetCls.getFields()) { // handleField(name, f, handledFields, result, targetCls, ref, contextPath, typeRules, schematizer); // } // // return result.entrySet().stream().sorted(byPath).collect(Collectors.toMap(Entry::getKey, Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new)); // } // // @SuppressWarnings( { "rawtypes", "unchecked" } ) // private static void handleField( // String name, // Field field, // Set<String> handledFields, // Map<String, NodeImpl> result, // Class<?> targetCls, // TypeReference<?> ref, // String contextPath, // Map<String, Object> rules, // SchematizerImplOLD schematizer) { // if (Modifier.isStatic(field.getModifiers())) // return; // // String fieldName = field.getName(); // if (handledFields.contains(fieldName)) // return; // Field with this name was already handled // // try { // String path = contextPath + "/" + fieldName; // NodeImpl node; // if (rules.containsKey(path)) { // // The actual field. Since the type for this node is provided as a rule, we // // only need it to test whether or not it is a collection. // Class<?> actualFieldType = field.getType(); // boolean isCollection = Collection.class.isAssignableFrom(actualFieldType); // Class<?> rawClass = rawClassOf(rules.get(path)); // // This is the type we will persist in the Schema (as provided by the rules), NOT the "actual" field type. // SchemaImpl embedded = SchematizerImplOLD.internalSchematize(name, path, rules, isCollection, schematizer); // Class<?> fieldClass = Util.primitiveToBoxed(rawClass); // TypeReference fieldRef = typeReferenceOf(rules.get(path)); // if (isCollection) // node = new CollectionNode( // field.getName(), // fieldRef, // path, // (Class)actualFieldType); // else if (fieldRef != null ) // node = new NodeImpl(fieldName, fieldRef, false, path); // else // node = new NodeImpl(fieldName, fieldClass, false, path); // Map<String, NodeImpl> allNodes = embedded.toMapInternal(); // allNodes.remove(path + "/"); // result.putAll(allNodes); // Map<String, NodeImpl> childNodes = extractChildren(path, allNodes); // node.add(childNodes); // } else { // Type fieldType = field.getType(); // Class<?> rawClass = rawClassOf(fieldType); // Class<?> fieldClass = Util.primitiveToBoxed(rawClass); // // if (Collection.class.isAssignableFrom(fieldClass)) { // CollectionType collectionTypeAnnotation = field.getAnnotation( CollectionType.class ); // Class<?> collectionType; // if (collectionTypeAnnotation != null) // collectionType = collectionTypeAnnotation.value(); // else if (hasCollectionTypeAnnotation(field)) // collectionType = collectionTypeOf(field); // else // collectionType = Object.class; // node = new CollectionNode( // field.getName(), // collectionType, // path, // (Class)fieldClass); // // if (DTO.class.isAssignableFrom(collectionType)) { // SchematizerImplOLD newSchematizer = new SchematizerImplOLD(); // newSchematizer.typeRules.put(path, rules); // if (!rules.containsKey(path)) // newSchematizer.rule(path, path, collectionType); // SchemaImpl embedded = newSchematizer.schematize(path, path); // Map<String, NodeImpl> allNodes = embedded.toMapInternal(); // allNodes.remove(path + "/"); // result.putAll(allNodes); // Map<String, NodeImpl> childNodes = extractChildren(path, allNodes); // node.add(childNodes); // } // } // else if (DTO.class.isAssignableFrom(fieldClass)) { // SchematizerImplOLD newSchematizer = new SchematizerImplOLD(); // newSchematizer.typeRules.put(path, rules); // if (!rules.containsKey(path)) // newSchematizer.rule(path, path, fieldClass); // SchemaImpl embedded = newSchematizer.schematize(path, path); // node = new NodeImpl( // field.getName(), // fieldClass, // false, // path); // Map<String, NodeImpl> allNodes = embedded.toMapInternal(); // allNodes.remove(path + "/"); // result.putAll(allNodes); // Map<String, NodeImpl> childNodes = extractChildren(path, allNodes); // node.add(childNodes); // } else { // node = new NodeImpl( // field.getName(), // fieldClass, // false, // path); // } // } // // result.put(node.absolutePath(), node); // handledFields.add(fieldName); // } catch (Exception e) { // // Ignore this field // // TODO print warning?? // return; // } // } // // private static Map<String, NodeImpl> extractChildren( String path, Map<String, NodeImpl> allNodes ) { // final Map<String, NodeImpl> children = new HashMap<>(); // for (String key : allNodes.keySet()) { // String newKey = key.replace(path, ""); // if (!newKey.substring(1).contains("/")) // children.put( newKey, allNodes.get(key)); // } // // return children; // } // // private static SchemaImpl handleInvalid() { // // TODO // return null; // } // // private static Class<?> rawClassOf(Object type) { // Class<?> rawClass = null; // if (type instanceof Class) { // rawClass = (Class<?>)type; // } else if (type instanceof ParameterizedType) { // ParameterizedType paramType = (ParameterizedType) type; // Type rawType = paramType.getRawType(); // if (rawType instanceof Class) // rawClass = (Class<?>)rawType; // } else if (type instanceof TypeReference) { // return rawClassOf(((TypeReference<?>)type).getType()); // } // // return rawClass; // } // // private static TypeReference<?> typeReferenceOf(Object type) { // TypeReference<?> typeRef = null; // if (type instanceof TypeReference) // typeRef = (TypeReference<?>)type; // return typeRef; // } // // public static class Instantiator implements Function<String, Type> { // private final List<ClassLoader> classloaders = new ArrayList<>(); // // public Instantiator(List<ClassLoader> aClassLoadersList) { // classloaders.addAll( aClassLoadersList ); // } // // @Override // public Type apply(String className) { // for (ClassLoader cl : classloaders) { // try { // return cl.loadClass(className); // } catch (ClassNotFoundException e) { // // Try next // } // } // // // Could not find the class. Try "this" ClassLoader // try { // return getClass().getClassLoader().loadClass(className); // } catch (ClassNotFoundException e) { // // Too bad // } // // // Nothing to do. Return Object.class as the fallback // return Object.class; // } // } // // static private void associateChildNodes(NodeImpl rootNode) { // for (NodeImpl child: rootNode.childrenInternal().values()) { // child.parent(rootNode); // String fieldName = child.name(); // Class<?> parentClass = rawClassOf(rootNode.type()); // try { // Field field = parentClass.getField(fieldName); // child.field(field); // } catch ( NoSuchFieldException e ) { // e.printStackTrace(); // } // // associateChildNodes(child); // } // } // // static private boolean hasCollectionTypeAnnotation(Field field) { // if (field == null) // return false; // // Annotation[] annotations = field.getAnnotations(); // if (annotations.length == 0) // return false; // // return Arrays.stream(annotations) // .map(a -> a.annotationType().getName()) // .anyMatch(a -> "CollectionType".equals(a.substring(a.lastIndexOf(".") + 1) )); // } // // static private Class<?> collectionTypeOf(Field field) { // Annotation[] annotations = field.getAnnotations(); // // Annotation annotation = Arrays.stream(annotations) // .filter(a -> "CollectionType".equals(a.annotationType().getName().substring(a.annotationType().getName().lastIndexOf(".") + 1) )) // .findFirst() // .get(); // // try { // Method m = annotation.annotationType().getMethod("value"); // Class<?> value = (Class<?>)m.invoke(annotation, (Object[])null); // return value; // } catch ( Exception e ) { // return null; // } // } //}