Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

YOML = YAML object mapping language [BIG!] #363

Open
wants to merge 93 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
93 commits
Select commit Hold shift + click to select a range
1108d8f
bump httpcomponents versions
ahgittin Sep 30, 2016
a319156
Start work on YAML Object Relational Mapping Language
ahgittin Jun 9, 2016
97c1226
flesh out much more of YORML
ahgittin Jun 24, 2016
9c16de6
more YORML improvements, now dealing with fields in fields, primtives…
ahgittin Jun 24, 2016
0f50906
more yorml - implicit types and fail on incomplete read
ahgittin Jun 24, 2016
77aafab
notes for explicit-field, failing test, and preparatory refactor
ahgittin Jun 27, 2016
ed25f09
explicit fields basic working for expected types
ahgittin Jun 27, 2016
39a5792
explicit fields working also for declared types
ahgittin Jun 27, 2016
c562d5c
WIP handling defaults, before switching to phases
ahgittin Jun 27, 2016
7c91683
switching to using phases for YORML conversion
ahgittin Jun 27, 2016
cd73104
serializers are inherited and explicit-field respects multiple/inherited
ahgittin Jun 27, 2016
e51310e
explicit-field alias control: inherit and exclude field name
ahgittin Jun 27, 2016
dc65327
name mangling for explicit-field, and tidies around constraint
ahgittin Jun 27, 2016
493dead
support lists/sets, and tidy
ahgittin Jun 28, 2016
80b0feb
misc utils minor improvements
ahgittin Jun 29, 2016
0172445
add yorml map support, fix list support, other minor fixes
ahgittin Jun 29, 2016
85476ab
support enums
ahgittin Jun 29, 2016
cd4f9a4
easy way to make all fields explicit, and related fixes
ahgittin Jun 29, 2016
fa9535a
support generics from fields for map/list/set
ahgittin Jun 29, 2016
e4235f3
support clever parsing of singleton maps
ahgittin Jun 30, 2016
8d5409e
yorml notes
ahgittin Aug 12, 2016
41a1ca5
rename it YOML as it's not relational
Aug 31, 2016
f930271
docs tweaks
Aug 31, 2016
df4c709
minor yoml improvements
ahgittin Sep 5, 2016
b3e5169
camp yoml transformer and type-registry integration fleshing out
Sep 2, 2016
0abcd6b
serializers and supertypes/java-type
ahgittin Sep 7, 2016
8e80c6a
support annotations for serializers
ahgittin Sep 7, 2016
928089e
support yoml annotations in transformer
ahgittin Sep 7, 2016
bcd65dd
support `$brooklyn:object-yoml` in DSL
ahgittin Sep 8, 2016
52a2009
background type coercion extensions
ahgittin Sep 8, 2016
617417c
support resolution of objects eg $brooklyn dsl suppliers within yoml …
ahgittin Sep 8, 2016
6252a8a
support $brooklyn dsl when *parsing* yoml input
ahgittin Sep 9, 2016
4fad3c2
tidy how explicit field annotations are detected
ahgittin Sep 9, 2016
1ff3ca7
add config-key constructor support
ahgittin Sep 12, 2016
9aaa2ed
cleanups of config key handling, including nesting and annotations
ahgittin Sep 12, 2016
106203f
brooklyn yoml supports ConfigBag as well as map constructors
ahgittin Sep 12, 2016
6c15226
add/improve convert-map, and major renames (from "ExplicitField" to "…
ahgittin Sep 13, 2016
1c5bbb4
repair MockConfigKey interface in light of config inheritance changes
ahgittin Sep 22, 2016
7110e9b
update sketch for next set of serializers
ahgittin Sep 13, 2016
ca6c384
serializer to convert explicitly from primitive to map
ahgittin Sep 13, 2016
0da7caa
support renaming of keys
ahgittin Sep 13, 2016
07a5576
bail out in singleton-map conversion
ahgittin Sep 13, 2016
c0d1918
add default map values serializer, and fix spelling
ahgittin Sep 13, 2016
0328555
big yoml refactor, and fixes to map conversion to restrict scope
ahgittin Sep 13, 2016
c84643b
sensors/effectors wip
ahgittin Sep 13, 2016
31662ae
support generics in config keys in yoml
ahgittin Sep 22, 2016
40e587f
add Asserts.assertPresent and NotPresent for working with maybes
ahgittin Sep 26, 2016
669b95e
tidy and test findConstructor methods
ahgittin Sep 26, 2016
3650234
prep for using config inheritance strategies, incl failing test and r…
ahgittin Sep 22, 2016
12d530f
config key inheritance strategies working within yoml
ahgittin Sep 22, 2016
4f92b50
config map/bag can be passed to constructor even if not stored as field
ahgittin Sep 27, 2016
52ccd7c
yoml allows one key to specify the type of another key
ahgittin Sep 27, 2016
6e013ee
support config key's type coming from another config key
ahgittin Sep 27, 2016
45d435c
static sensor loaded via yoml !!!
ahgittin Sep 27, 2016
db64b33
tidy of yoml, being stricter and clearer
ahgittin Sep 28, 2016
f4c41ca
improve yoml coercion to/from primitive, and use that for duration
ahgittin Sep 28, 2016
bb03422
prevent primitive coercion from applying to items with generics or js…
ahgittin Sep 29, 2016
2d20a52
improve output of yoml when going via brooklyn registry
ahgittin Sep 28, 2016
87b4e50
tidy freemarker code
ahgittin Sep 28, 2016
47584d1
pass yoml context to type registry so it can do the right lookups
ahgittin Sep 29, 2016
02a67a7
simplify logging
ahgittin Sep 29, 2016
d0635d7
when reading yoml if we've gotten a deferred Supplier just accept it
ahgittin Sep 29, 2016
677eb79
inherit annotations for renaming keys better
ahgittin Sep 29, 2016
5827fbf
correctly set defaults for fields and config in edge cases
ahgittin Sep 29, 2016
a94ec57
use type tokens for structured (map, list) config keys
ahgittin Sep 29, 2016
d6555ef
test ssh sensors and effectors from yoml
ahgittin Sep 29, 2016
3b39790
support lists better in yoml, and better logging output
ahgittin Sep 30, 2016
70bf955
resolve deferred values at the right time in yoml (ie as late as poss…
ahgittin Sep 30, 2016
a3833cf
change google client api joiner to base guava one
ahgittin Oct 26, 2016
af823d6
Merge branch 'master' into yoml
ahgittin Nov 13, 2016
c32d891
Merge branch 'master' into yoml
Dec 6, 2016
ce60526
Merge branch 'master' into yoml
ahgittin Feb 14, 2017
cff3118
Merge branch 'master' into yoml
ahgittin Feb 15, 2017
4a78cb2
Merge branch 'master' into yoml
ahgittin Feb 27, 2017
0d73e76
remove generic params from `AddSensor`, just put it in classes where …
ahgittin Feb 27, 2017
26a4c57
Revert "bump httpcomponents versions"
ahgittin Feb 27, 2017
adcd1ed
Merge branch 'master' into yoml
ahgittin Mar 7, 2017
a4e2654
Merge branch 'master' into yoml
ahgittin May 2, 2017
cbe03dc
Merge branch 'master' into yoml
ahgittin May 3, 2017
6869f7c
Merge branch 'master' into yoml
ahgittin Jun 5, 2017
b409423
fix ambiguous/generics references w move to Java 8
ahgittin Jun 5, 2017
93f60d2
Merge branch 'master' into yoml
ahgittin Jun 23, 2017
4558a0b
Merge branch 'master' into yoml
ahgittin Jul 5, 2017
3c96ecc
Merge branch 'master' into yoml
ahgittin Jul 22, 2017
779095e
update mock to compile with master
ahgittin Jul 22, 2017
91b6828
Merge branch 'master' into yoml3
ahgittin Aug 29, 2017
45fe58a
fixes for visibility/changes to `params` field
ahgittin Aug 29, 2017
e18affa
Merge branch 'uninstall-bundles-on-error' into yoml3
ahgittin Aug 29, 2017
14bcad3
placeholders for getting RegisteredType supertypes from a RT
ahgittin Jan 17, 2018
1ecd8cd
Merge branch 'master' into yoml
ahgittin Jan 25, 2018
79174c9
fix compile/runtime errors due to incompatible changes
ahgittin Jan 25, 2018
3f9b30c
Merge branch 'supertypes-RT' into yoml
ahgittin Jan 25, 2018
802666a
make YOML code compatible with supertype/typeinfo API extension
ahgittin Jan 25, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,26 @@
import org.apache.brooklyn.api.objs.EntityAdjunct;
import org.apache.brooklyn.api.policy.Policy;
import org.apache.brooklyn.api.sensor.Feed;
import org.apache.brooklyn.util.yoml.annotations.Alias;
import org.apache.brooklyn.util.yoml.annotations.YomlSingletonMap;

/**
* Instances of this class supply logic which can be used to initialize entities.
* These can be added to an {@link EntitySpec} programmatically, or declared as part
* of YAML recipes in a <code>brooklyn.initializers</code> section.
* In the case of the latter, implementing classes should define a no-arg constructor
* or a {@link Map} constructor so that YAML parameters can be supplied.
* <p>
* When intended for use from YAML, implementing classes should define
* a single-argument constructor taking either a {@link Map} or a ConfigBag
* so that YAML parameters can be supplied
* (or a no-arg constructor if parameters are not supported).
* <p>
* Note that initializers are only invoked on first creation; they are not called
* during a rebind. Instead, the typical pattern is that initializers will create
* {@link EntityAdjunct} instances such as {@link Policy} and {@link Feed}
* which will be attached during rebind.
**/
@YomlSingletonMap(keyForPrimitiveValue="type")
@Alias("entity-initializer")
public interface EntityInitializer {

/** Applies initialization logic to a just-built entity.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.apache.brooklyn.api.entity.EntitySpec;
import org.apache.brooklyn.api.mgmt.classloading.BrooklynClassLoadingContext;
import org.apache.brooklyn.api.typereg.BrooklynTypeRegistry.RegisteredTypeKind;
import org.apache.brooklyn.util.yoml.internal.ConstructionInstruction;

public interface RegisteredTypeLoadingContext {

Expand All @@ -37,6 +38,7 @@ public interface RegisteredTypeLoadingContext {
* for specs, this refers to the target type, not the spec
* (eg {@link Entity} not {@link EntitySpec}).
* If nothing is specified, this returns {@link Object}'s class. */
// TODO extend to offer expected registered super type
@Nonnull public Class<?> getExpectedJavaSuperType();

/** encountered types, so that during resolution,
Expand All @@ -47,4 +49,9 @@ public interface RegisteredTypeLoadingContext {
/** A loader to use, supplying preferred or additional bundles and search paths */
@Nullable public BrooklynClassLoadingContext getLoader();

/** Optional instructions on how to invoke the constructor,
* for use when a caller needs to specify a special constructor or factory method
* and/or specify parameters */
@Nullable public ConstructionInstruction getConstructorInstruction();

}
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,15 @@
import org.apache.brooklyn.api.typereg.RegisteredType;
import org.apache.brooklyn.camp.brooklyn.BrooklynCampReservedKeys;
import org.apache.brooklyn.camp.brooklyn.spi.creation.BrooklynYamlTypeInstantiator.InstantiatorFromKey;
import org.apache.brooklyn.camp.brooklyn.spi.dsl.DslAccessible;
import org.apache.brooklyn.camp.brooklyn.spi.dsl.methods.BrooklynDslCommon;
import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
import org.apache.brooklyn.core.mgmt.BrooklynTags;
import org.apache.brooklyn.core.objs.BasicSpecParameter;
import org.apache.brooklyn.core.typereg.RegisteredTypeLoadingContexts;
import org.apache.brooklyn.core.typereg.RegisteredTypes;
import org.apache.brooklyn.util.collections.MutableList;
import org.apache.brooklyn.util.collections.MutableMap;
import org.apache.brooklyn.util.core.config.ConfigBag;
import org.apache.brooklyn.util.core.task.DeferredSupplier;
import org.apache.brooklyn.util.guava.Maybe;
Expand Down Expand Up @@ -77,13 +80,18 @@ protected List<? extends DT> buildListOfTheseDecorationsFromEntityAttributes(Con
if (value==null) { return MutableList.of(); }
if (value instanceof Iterable) {
return buildListOfTheseDecorationsFromIterable((Iterable<?>)value);
} else if (canBuildFromMap()) {
if (value instanceof Map) {
return buildListOfTheseDecorationsFromMap((Map<?,?>)value);
} else {
throw new IllegalArgumentException(getDecorationKind()+" body should be map or iterable, not " + value.getClass());
}
} else {
// in future may support types other than iterables here,
// e.g. a map short form where the key is the type
throw new IllegalArgumentException(getDecorationKind()+" body should be iterable, not " + value.getClass());
}
}


protected Map<?,?> checkIsMap(Object decorationJson) {
if (!(decorationJson instanceof Map)) {
throw new IllegalArgumentException(getDecorationKind()+" value must be a Map, not " +
Expand All @@ -100,6 +108,11 @@ protected List<DT> buildListOfTheseDecorationsFromIterable(Iterable<?> value) {
return decorations;
}

// optional if syntax supports a map input
// (e.g. where the key is the type or the name)
protected boolean canBuildFromMap() { return false; }
protected List<DT> buildListOfTheseDecorationsFromMap(Map<?, ?> value) { throw new UnsupportedOperationException(); }

protected abstract String getDecorationKind();

protected abstract Object getDecorationAttributeJsonValue(ConfigBag attrs);
Expand Down Expand Up @@ -201,6 +214,22 @@ protected Object getDecorationAttributeJsonValue(ConfigBag attrs) {
protected void addDecorationFromJsonMap(Map<?, ?> decorationJson, List<EntityInitializer> decorations) {
decorations.add(instantiator.from(decorationJson).prefix("initializer").newInstance(EntityInitializer.class));
}

@Override
protected boolean canBuildFromMap() {
return true;
}

@Override
protected List<EntityInitializer> buildListOfTheseDecorationsFromMap(Map<?, ?> value) {
ManagementContext mgmt = instantiator.loader.getManagementContext();
List<EntityInitializer> result = MutableList.of();
for (Map.Entry<?, ?> v: value.entrySet()) {
result.add(mgmt.getTypeRegistry().createBeanFromPlan("yoml", MutableMap.of(v.getKey(), v.getValue()),
RegisteredTypeLoadingContexts.loader(instantiator.loader), EntityInitializer.class));
}
return result;
}
}

// Not much value from extending from BrooklynEntityDecorationResolver, but let's not break the convention
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,14 +126,14 @@ public boolean apply(Object deploymentPlanItem, AssemblyTemplateConstructor atc)
brooklynFlags.putAll((Map<?,?>)origBrooklynFlags);
}

addCustomMapAttributeIfNonNull(builder, attrs, BrooklynCampReservedKeys.BROOKLYN_CONFIG);
addCustomListAttributeIfNonNull(builder, attrs, BrooklynCampReservedKeys.BROOKLYN_POLICIES);
addCustomListAttributeIfNonNull(builder, attrs, BrooklynCampReservedKeys.BROOKLYN_ENRICHERS);
addCustomListAttributeIfNonNull(builder, attrs, BrooklynCampReservedKeys.BROOKLYN_INITIALIZERS);
addCustomListAttributeIfNonNull(builder, attrs, BrooklynCampReservedKeys.BROOKLYN_CHILDREN);
addCustomListAttributeIfNonNull(builder, attrs, BrooklynCampReservedKeys.BROOKLYN_PARAMETERS);
addCustomMapAttributeIfNonNull(builder, attrs, BrooklynCampReservedKeys.BROOKLYN_CATALOG);
addCustomListAttributeIfNonNull(builder, attrs, BrooklynCampReservedKeys.BROOKLYN_TAGS);
addCustomMapAttributeIfNonEmpty(builder, attrs, BrooklynCampReservedKeys.BROOKLYN_CONFIG);
addCustomListAttributeIfNonEmpty(builder, attrs, BrooklynCampReservedKeys.BROOKLYN_POLICIES);
addCustomListAttributeIfNonEmpty(builder, attrs, BrooklynCampReservedKeys.BROOKLYN_ENRICHERS);
addCustomAttributeIfNonEmpty(builder, attrs, BrooklynCampReservedKeys.BROOKLYN_INITIALIZERS, true, true);
addCustomListAttributeIfNonEmpty(builder, attrs, BrooklynCampReservedKeys.BROOKLYN_CHILDREN);
addCustomListAttributeIfNonEmpty(builder, attrs, BrooklynCampReservedKeys.BROOKLYN_PARAMETERS);
addCustomMapAttributeIfNonEmpty(builder, attrs, BrooklynCampReservedKeys.BROOKLYN_CATALOG);
addCustomListAttributeIfNonEmpty(builder, attrs, BrooklynCampReservedKeys.BROOKLYN_TAGS);

brooklynFlags.putAll(attrs);
if (!brooklynFlags.isEmpty()) {
Expand All @@ -150,35 +150,37 @@ public boolean apply(Object deploymentPlanItem, AssemblyTemplateConstructor atc)
* as a custom attribute with type List.
* @throws java.lang.IllegalArgumentException if map[key] is not an instance of List
*/
private void addCustomListAttributeIfNonNull(Builder<? extends PlatformComponentTemplate> builder, Map<?,?> attrs, String key) {
Object items = attrs.remove(key);
if (items != null) {
if (items instanceof List) {
List<?> itemList = (List<?>) items;
if (!itemList.isEmpty()) {
builder.customAttribute(key, Lists.newArrayList(itemList));
}
} else {
throw new IllegalArgumentException(key + " must be a list, is: " + items.getClass().getName());
}
}
private void addCustomListAttributeIfNonEmpty(Builder<? extends PlatformComponentTemplate> builder, Map<?,?> attrs, String key) {
addCustomAttributeIfNonEmpty(builder, attrs, key, false, true);
}

/**
* Looks for the given key in the map of attributes and adds it to the given builder
* as a custom attribute with type Map.
* @throws java.lang.IllegalArgumentException if map[key] is not an instance of Map
*/
private void addCustomMapAttributeIfNonNull(Builder<? extends PlatformComponentTemplate> builder, Map<?,?> attrs, String key) {
private void addCustomMapAttributeIfNonEmpty(Builder<? extends PlatformComponentTemplate> builder, Map<?,?> attrs, String key) {
addCustomAttributeIfNonEmpty(builder, attrs, key, true, false);
}

private void addCustomAttributeIfNonEmpty(Builder<? extends PlatformComponentTemplate> builder, Map<?,?> attrs, String key,
boolean allowMap, boolean allowList) {
Object items = attrs.remove(key);
if (items != null) {
if (items instanceof Map) {
if (allowMap && items instanceof Map) {
Map<?, ?> itemMap = (Map<?, ?>) items;
if (!itemMap.isEmpty()) {
builder.customAttribute(key, Maps.newHashMap(itemMap));
}
} else if (allowList && items instanceof List) {
List<?> itemList = (List<?>) items;
if (!itemList.isEmpty()) {
builder.customAttribute(key, Lists.newArrayList(itemList));
}
} else {
throw new IllegalArgumentException(key + " must be a map, is: " + items.getClass().getName());
throw new IllegalArgumentException(key + " must be a "+
(allowMap && allowList ? "map or list" : allowMap ? "map" : allowList ? "list" : "<no type allowed>")+
", is: " + items.getClass().getName());
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,16 @@
import java.util.Map;

import org.apache.brooklyn.api.internal.AbstractBrooklynObjectSpec;
import org.apache.brooklyn.api.typereg.BrooklynTypeRegistry.RegisteredTypeKind;
import org.apache.brooklyn.api.typereg.RegisteredType;
import org.apache.brooklyn.api.typereg.RegisteredType.TypeImplementationPlan;
import org.apache.brooklyn.api.typereg.RegisteredTypeLoadingContext;
import org.apache.brooklyn.api.typereg.BrooklynTypeRegistry.RegisteredTypeKind;
import org.apache.brooklyn.core.typereg.AbstractFormatSpecificTypeImplementationPlan;
import org.apache.brooklyn.core.typereg.AbstractTypePlanTransformer;
import org.apache.brooklyn.core.typereg.BasicTypeImplementationPlan;
import org.apache.brooklyn.core.typereg.RegisteredTypeInfo;
import org.apache.brooklyn.core.typereg.RegisteredTypes;
import org.apache.brooklyn.util.collections.MutableSet;
import org.apache.brooklyn.util.guava.Maybe;

import com.google.common.collect.ImmutableList;
Expand Down Expand Up @@ -84,28 +86,24 @@ protected double scoreForNonmatchingNonnullFormat(String planFormat, Object plan

@Override
protected AbstractBrooklynObjectSpec<?, ?> createSpec(RegisteredType type, RegisteredTypeLoadingContext context) throws Exception {
// TODO cache
// could cache and copy each time, if this bit is slow
// (but don't think it is now)
return new CampResolver(mgmt, type, context).createSpec();
}

@Override
protected Object createBean(RegisteredType type, RegisteredTypeLoadingContext context) throws Exception {
// beans not supported by this?
// beans not supported by this? - want YOML for this
throw new IllegalStateException("beans not supported here");
}

@Override
public double scoreForTypeDefinition(String formatCode, Object catalogData) {
// TODO catalog parsing
return 0;
}

@Override
public List<RegisteredType> createFromTypeDefinition(String formatCode, Object catalogData) {
// TODO catalog parsing
return null;
public RegisteredTypeInfo getTypeInfo(RegisteredType type) {
// TODO collect immediate supertypes, as RegisteredType and Class instances
// we really want YOML for this however
return RegisteredTypeInfo.create(type, this, null, MutableSet.of());
}

public static class CampTypeImplementationPlan extends AbstractFormatSpecificTypeImplementationPlan<String> {
public CampTypeImplementationPlan(TypeImplementationPlan otherPlan) {
super(FORMATS.get(0), String.class, otherPlan);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.CaseFormat;

/**
* {@link PlanInterpreter} which understands the $brooklyn DSL
*/
Expand Down Expand Up @@ -156,6 +158,9 @@ public Object evaluateOn(Object o, FunctionWithArgs f, boolean deepEvaluation) {

String fn = f.getFunction();
fn = Strings.removeFromStart(fn, BrooklynDslCommon.PREFIX);
if (fn.contains("-")) {
fn = CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL, fn);
}
if (fn.startsWith("function.")) {
// If the function name starts with 'function.', then we look for the function in BrooklynDslCommon.Functions
// As all functions in BrooklynDslCommon.Functions are static, we don't need to worry whether a class
Expand Down
Loading