Return-Path: X-Original-To: apmail-brooklyn-dev-archive@minotaur.apache.org Delivered-To: apmail-brooklyn-dev-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id CFDA618531 for ; Thu, 12 Nov 2015 10:21:54 +0000 (UTC) Received: (qmail 70479 invoked by uid 500); 12 Nov 2015 10:21:54 -0000 Delivered-To: apmail-brooklyn-dev-archive@brooklyn.apache.org Received: (qmail 70444 invoked by uid 500); 12 Nov 2015 10:21:54 -0000 Mailing-List: contact dev-help@brooklyn.incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@brooklyn.incubator.apache.org Delivered-To: mailing list dev@brooklyn.incubator.apache.org Received: (qmail 70433 invoked by uid 99); 12 Nov 2015 10:21:54 -0000 Received: from Unknown (HELO spamd1-us-west.apache.org) (209.188.14.142) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 12 Nov 2015 10:21:54 +0000 Received: from localhost (localhost [127.0.0.1]) by spamd1-us-west.apache.org (ASF Mail Server at spamd1-us-west.apache.org) with ESMTP id 143F5C5F6E for ; Thu, 12 Nov 2015 10:21:54 +0000 (UTC) X-Virus-Scanned: Debian amavisd-new at spamd1-us-west.apache.org X-Spam-Flag: NO X-Spam-Score: 0.578 X-Spam-Level: X-Spam-Status: No, score=0.578 tagged_above=-999 required=6.31 tests=[KAM_LAZY_DOMAIN_SECURITY=1, RCVD_IN_MSPIKE_H3=-0.01, RCVD_IN_MSPIKE_WL=-0.01, RP_MATCHES_RCVD=-0.403, URIBL_BLOCKED=0.001] autolearn=disabled Received: from mx1-eu-west.apache.org ([10.40.0.8]) by localhost (spamd1-us-west.apache.org [10.40.0.7]) (amavisd-new, port 10024) with ESMTP id H6LxZ8UFZQsd for ; Thu, 12 Nov 2015 10:21:44 +0000 (UTC) Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by mx1-eu-west.apache.org (ASF Mail Server at mx1-eu-west.apache.org) with SMTP id 0A97E20512 for ; Thu, 12 Nov 2015 10:21:42 +0000 (UTC) Received: (qmail 70353 invoked by uid 99); 12 Nov 2015 10:21:42 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 12 Nov 2015 10:21:42 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 270C8E5DFE; Thu, 12 Nov 2015 10:21:42 +0000 (UTC) From: neykov To: dev@brooklyn.incubator.apache.org Reply-To: dev@brooklyn.incubator.apache.org References: In-Reply-To: Subject: [GitHub] incubator-brooklyn pull request: Flesh out type creation using the... Content-Type: text/plain Message-Id: <20151112102142.270C8E5DFE@git1-us-west.apache.org> Date: Thu, 12 Nov 2015 10:21:42 +0000 (UTC) Github user neykov commented on a diff in the pull request: https://github.com/apache/incubator-brooklyn/pull/1017#discussion_r44640885 --- Diff: core/src/main/java/org/apache/brooklyn/core/typereg/RegisteredTypeLoadingContexts.java --- @@ -0,0 +1,236 @@ +/* + * 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.brooklyn.core.typereg; + +import groovy.xml.Entity; + +import java.util.Set; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import org.apache.brooklyn.api.entity.EntitySpec; +import org.apache.brooklyn.api.internal.AbstractBrooklynObjectSpec; +import org.apache.brooklyn.api.mgmt.classloading.BrooklynClassLoadingContext; +import org.apache.brooklyn.api.objs.BrooklynObject; +import org.apache.brooklyn.api.objs.BrooklynObjectType; +import org.apache.brooklyn.api.typereg.BrooklynTypeRegistry.RegisteredTypeKind; +import org.apache.brooklyn.api.typereg.RegisteredTypeLoadingContext; +import org.apache.brooklyn.util.collections.MutableSet; +import org.apache.brooklyn.util.javalang.JavaClassNames; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.collect.ImmutableSet; + +public class RegisteredTypeLoadingContexts { + + private static final Logger log = LoggerFactory.getLogger(RegisteredTypeLoadingContexts.BasicRegisteredTypeLoadingContext.class); + + /** Immutable (from caller's perspective) record of a constraint */ + public final static class BasicRegisteredTypeLoadingContext implements RegisteredTypeLoadingContext { + @Nullable private RegisteredTypeKind kind; + @Nullable private Class expectedSuperType; + @Nonnull private Set encounteredTypes = ImmutableSet.of(); + @Nullable BrooklynClassLoadingContext loader; + + private BasicRegisteredTypeLoadingContext() {} + + public BasicRegisteredTypeLoadingContext(@Nullable RegisteredTypeLoadingContext source) { + if (source==null) return; + + this.kind = source.getExpectedKind(); + this.expectedSuperType = source.getExpectedJavaSuperType(); + this.encounteredTypes = source.getAlreadyEncounteredTypes(); + this.loader = (BrooklynClassLoadingContext) source.getLoader(); + } + + @Override + public RegisteredTypeKind getExpectedKind() { + return kind; + } + + @Override + public Class getExpectedJavaSuperType() { + if (expectedSuperType==null) return Object.class; + return expectedSuperType; + } + + @Override + public Set getAlreadyEncounteredTypes() { + if (encounteredTypes==null) return ImmutableSet.of(); + return ImmutableSet.copyOf(encounteredTypes); + } + + @Override + public BrooklynClassLoadingContext getLoader() { + return loader; + } + + @Override + public String toString() { + return JavaClassNames.cleanSimpleClassName(this)+"["+kind+","+expectedSuperType+","+encounteredTypes+"]"; + } + } + + /** returns a constraint which allows anything */ + public static RegisteredTypeLoadingContext any() { + return new BasicRegisteredTypeLoadingContext(); + } + + public static RegisteredTypeLoadingContext alreadyEncountered(Set encounteredTypeSymbolicNames) { + BasicRegisteredTypeLoadingContext result = new BasicRegisteredTypeLoadingContext(); + result.encounteredTypes = encounteredTypeSymbolicNames == null ? ImmutableSet.of() : ImmutableSet.copyOf(encounteredTypeSymbolicNames); + return result; + } + public static RegisteredTypeLoadingContext alreadyEncountered(Set encounteredTypeSymbolicNames, String anotherEncounteredType) { + BasicRegisteredTypeLoadingContext result = new BasicRegisteredTypeLoadingContext(); + MutableSet encounteredTypes = MutableSet.copyOf(encounteredTypeSymbolicNames); + encounteredTypes.addIfNotNull(anotherEncounteredType); + result.encounteredTypes = encounteredTypes.asUnmodifiable(); + return result; + } + + public static RegisteredTypeLoadingContext loaderAlreadyEncountered(BrooklynClassLoadingContext loader, Set encounteredTypeSymbolicNames) { + return loaderAlreadyEncountered(loader, encounteredTypeSymbolicNames, null); + } + public static RegisteredTypeLoadingContext loaderAlreadyEncountered(BrooklynClassLoadingContext loader, Set encounteredTypeSymbolicNames, String anotherEncounteredType) { + return withLoader(alreadyEncountered(encounteredTypeSymbolicNames, anotherEncounteredType), loader); + } + + private static RegisteredTypeLoadingContext of(RegisteredTypeKind kind, Class javaSuperType) { + BasicRegisteredTypeLoadingContext result = new BasicRegisteredTypeLoadingContext(); + result.kind = kind; + result.expectedSuperType = javaSuperType; + return result; + } + + public static RegisteredTypeLoadingContext bean(Class javaSuperType) { + return of(RegisteredTypeKind.BEAN, javaSuperType); + } + + public static RegisteredTypeLoadingContext spec(Class javaSuperType) { + return of(RegisteredTypeKind.SPEC, javaSuperType); + } + + public static RegisteredTypeLoadingContext withBeanSuperType(@Nullable RegisteredTypeLoadingContext source, @Nullable Class beanSuperType) { + Class superType = beanSuperType; + BasicRegisteredTypeLoadingContext constraint = new BasicRegisteredTypeLoadingContext(source); + if (source==null) source = constraint; + if (superType==null) return source; + constraint.expectedSuperType = superType; + if (source.getExpectedJavaSuperType()==null || source.getExpectedJavaSuperType().isAssignableFrom( superType )) { + // the old constraint was weaker than present; return the new constraint + return constraint; + } + if (superType.isAssignableFrom( source.getExpectedJavaSuperType() )) { + // the constraint was already for something more specific; ignore what we've inferred here + return source; + } + log.warn("Ambiguous bean supertypes ("+beanSuperType+" for target "+source.getExpectedJavaSuperType()+"); " + + "it is recommended that any registered type constraint for a spec be compatible with the spec type"); + return source; + } + + /** Takes a Spec java type and adds an expected java type to the {@link RegisteredTypeLoadingContext} */ + public static > RegisteredTypeLoadingContext withSpecSuperType(@Nullable RegisteredTypeLoadingContext source, @Nullable Class specSuperType) { + Class superType = lookupTargetTypeForSpec(specSuperType); + BasicRegisteredTypeLoadingContext constraint = new BasicRegisteredTypeLoadingContext(source); + if (source==null) source = constraint; + if (superType==null) return source; + constraint.expectedSuperType = superType; + if (source.getExpectedJavaSuperType()==null || source.getExpectedJavaSuperType().isAssignableFrom( superType )) { + // the old constraint was weaker than present; return the new constraint + return constraint; + } + if (superType.isAssignableFrom( source.getExpectedJavaSuperType() )) { + // the constraint was already for something more specific; ignore what we've inferred here + return source; + } + // trickier situation; the constraint had a type not compatible with the spec type; log a warning and leave alone + // (e.g. caller specified some java super type which is not a super or sub of the spec target type; + // this may be because the caller specified a Spec as the type supertype, which is wrong; + // or they may have specified an interface along a different hierarchy, which we discouraged + // as it will make filtering/indexing more complex) + log.warn("Ambiguous spec supertypes ("+specSuperType+" for target "+source.getExpectedJavaSuperType()+"); " + + "it is recommended that any registered type constraint for a spec be compatible with the spec type"); + return source; + } + + /** given a spec, returns the class of the item it targets, for instance returns {@link Entity} given {@link EntitySpec}; + * see also {@link #lookupSpecTypeForTarget(Class)} */ + static > Class lookupTargetTypeForSpec(Class specSuperType) { + if (specSuperType==null) return BrooklynObject.class; + BrooklynObjectType best = null; + + for (BrooklynObjectType t: BrooklynObjectType.values()) { + if (t.getSpecType()==null) continue; + if (!t.getSpecType().isAssignableFrom(specSuperType)) continue; + // on equality, exit immediately + if (t.getSpecType().equals(specSuperType)) return t.getInterfaceType(); + // else pick which is best + if (best==null) { best = t; continue; } + // if t is more specific, it is better (handles case when e.g. a Policy is a subclass of Entity) + if (best.getSpecType().isAssignableFrom(t.getSpecType())) { best = t; continue; } + } + if (best==null) { + log.warn("Unexpected spec supertype ("+specSuperType+"); treating as any "+BrooklynObject.class, new Throwable("Trace for unexpected spec supertype")); + return BrooklynObject.class; + } + // the spec is more specific, but we're not familiar with it here; return the best + return best.getInterfaceType(); + } + + /** given a {@link BrooklynObject}, returns the spec class which would generate it, for instance returns {@link EntitySpec} given {@link Entity}, + * or null if not known */ + static Class> lookupSpecTypeForTarget(Class targetSuperType) { + if (targetSuperType==null) return null; + BrooklynObjectType best = null; + + for (BrooklynObjectType t: BrooklynObjectType.values()) { + if (t.getSpecType()==null) continue; + if (!t.getInterfaceType().isAssignableFrom(targetSuperType)) continue; + // on equality, exit immediately + if (t.getInterfaceType().equals(targetSuperType)) return t.getSpecType(); + // else pick which is best + if (best==null) { best = t; continue; } + // if t is more specific, it is better (handles case when e.g. a Policy is a subclass of Entity) + if (best.getSpecType().isAssignableFrom(t.getSpecType())) { best = t; continue; } --- End diff -- Again should be `getInterfaceType()` --- If your project is set up for it, you can reply to this email and have your reply appear on GitHub as well. If your project does not have this feature enabled and wishes so, or if the feature is enabled but not working, please contact infrastructure at infrastructure@apache.org or file a JIRA ticket with INFRA. ---