diff --git a/api/src/main/java/brooklyn/mementos/BrooklynCatalogMementoManifest.java b/api/src/main/java/brooklyn/mementos/BrooklynCatalogMementoManifest.java new file mode 100644 index 0000000000..c4b07c6d83 --- /dev/null +++ b/api/src/main/java/brooklyn/mementos/BrooklynCatalogMementoManifest.java @@ -0,0 +1,29 @@ +/* + * 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 brooklyn.mementos; + +import java.util.Collection; +import java.util.Map; + +public interface BrooklynCatalogMementoManifest { + CatalogItemMemento getCatalogItemMemento(String id); + Collection getCatalogItemIds(); + Map getCatalogItemMementos(); + boolean isEmpty(); +} diff --git a/api/src/main/java/brooklyn/mementos/BrooklynMementoManifest.java b/api/src/main/java/brooklyn/mementos/BrooklynMementoManifest.java index 6187e29cf5..c4b76f97f2 100644 --- a/api/src/main/java/brooklyn/mementos/BrooklynMementoManifest.java +++ b/api/src/main/java/brooklyn/mementos/BrooklynMementoManifest.java @@ -19,7 +19,6 @@ package brooklyn.mementos; import java.io.Serializable; -import java.util.Collection; import java.util.Map; import brooklyn.entity.trait.Identifiable; @@ -29,30 +28,26 @@ * * @author aled */ -public interface BrooklynMementoManifest extends Serializable { - public interface EntityMementoManifest extends Identifiable{ +public interface BrooklynMementoManifest extends BrooklynCatalogMementoManifest, Serializable { + public interface MementoManifest extends Identifiable { + @Override public String getId(); public String getType(); public String getParent(); public String getCatalogItemId(); } - public Map getEntityIdToManifest(); + public Map getEntityIdToManifest(); - public Map getLocationIdToType(); + public Map getLocationIdToManifest(); - public Map getPolicyIdToType(); + public Map getPolicyIdToManifest(); - public Map getEnricherIdToType(); + public Map getEnricherIdToManifest(); - public Map getFeedIdToType(); + public Map getFeedIdToManifest(); - public CatalogItemMemento getCatalogItemMemento(String id); - - public Collection getCatalogItemIds(); - - public Map getCatalogItemMementos(); - + @Override public boolean isEmpty(); } diff --git a/api/src/main/java/brooklyn/mementos/BrooklynMementoPersister.java b/api/src/main/java/brooklyn/mementos/BrooklynMementoPersister.java index ec16e9b2af..636f73933d 100644 --- a/api/src/main/java/brooklyn/mementos/BrooklynMementoPersister.java +++ b/api/src/main/java/brooklyn/mementos/BrooklynMementoPersister.java @@ -47,6 +47,7 @@ * Controls the persisting and reading back of mementos. Used by {@link RebindManager} * to support brooklyn restart. */ +//TODO should split into persistence data load/save; serializer/deserializer; persister daemon public interface BrooklynMementoPersister { public static interface LookupContext { @@ -73,6 +74,8 @@ public static interface LookupContext { */ BrooklynMementoRawData loadMementoRawData(RebindExceptionHandler exceptionHandler); + BrooklynCatalogMementoManifest loadCatalogMementos(BrooklynMementoRawData mementoData, RebindExceptionHandler exceptionHandler); + /** @deprecated since 0.7.0 use {@link #loadMementoManifest(BrooklynMementoRawData, RebindExceptionHandler)} */ BrooklynMementoManifest loadMementoManifest(RebindExceptionHandler exceptionHandler) throws IOException; diff --git a/core/src/main/java/brooklyn/catalog/internal/CatalogItemBuilder.java b/core/src/main/java/brooklyn/catalog/internal/CatalogItemBuilder.java index fb7a73501a..11f33f70f1 100644 --- a/core/src/main/java/brooklyn/catalog/internal/CatalogItemBuilder.java +++ b/core/src/main/java/brooklyn/catalog/internal/CatalogItemBuilder.java @@ -99,7 +99,7 @@ public CatalogItemBuilder deprecated(boolean deprecated) { return this; } - public CatalogItemBuilder libraries(Collection libraries) { + public CatalogItemBuilder libraries(Collection libraries) { dto.setLibraries(libraries); return this; } diff --git a/core/src/main/java/brooklyn/catalog/internal/CatalogItemDtoAbstract.java b/core/src/main/java/brooklyn/catalog/internal/CatalogItemDtoAbstract.java index 131c26ecd1..a79519968f 100644 --- a/core/src/main/java/brooklyn/catalog/internal/CatalogItemDtoAbstract.java +++ b/core/src/main/java/brooklyn/catalog/internal/CatalogItemDtoAbstract.java @@ -61,7 +61,7 @@ public abstract class CatalogItemDtoAbstract extends AbstractBrooklynO private @Deprecated @SetFromFlag String type; private @SetFromFlag String planYaml; - private @SetFromFlag Collection libraries; + private @SetFromFlag Collection libraries; private @SetFromFlag Set tags = Sets.newLinkedHashSet(); private @SetFromFlag boolean deprecated; @@ -337,7 +337,7 @@ protected void setPlanYaml(String planYaml) { this.planYaml = planYaml; } - protected void setLibraries(Collection libraries) { + protected void setLibraries(Collection libraries) { this.libraries = libraries; } diff --git a/core/src/main/java/brooklyn/entity/rebind/ActivePartialRebindIteration.java b/core/src/main/java/brooklyn/entity/rebind/ActivePartialRebindIteration.java index 76e600ada5..7b911c24d8 100644 --- a/core/src/main/java/brooklyn/entity/rebind/ActivePartialRebindIteration.java +++ b/core/src/main/java/brooklyn/entity/rebind/ActivePartialRebindIteration.java @@ -95,7 +95,7 @@ protected void doRun() throws Exception { * so there is a short window for data loss between this write and the subsequent read. */ @Override - protected void loadManifestFiles() throws Exception { + protected void loadRawMementos() { checkEnteringPhase(1); Builder mementoRawBuilder = BrooklynMementoRawData.builder(); @@ -125,10 +125,20 @@ protected void loadManifestFiles() throws Exception { } // then rebuild mementoRawData = mementoRawBuilder.build(); + } + + @Override + protected void instantiateCatalogMementos() { + checkEnteringPhase(2); + //NOP + } + @Override + protected void loadMementoManifest() throws Exception { + checkEnteringPhase(4); preprocessManifestFiles(); } - + @Override protected void preprocessManifestFiles() throws Exception { for (CompoundTransformer transformer: transformers) { @@ -140,8 +150,8 @@ protected void preprocessManifestFiles() throws Exception { @Override protected void rebuildCatalog() { - checkEnteringPhase(2); - + checkContinuingPhase(2); + // skip; old catalog items should be re-used } diff --git a/core/src/main/java/brooklyn/entity/rebind/InitialFullRebindIteration.java b/core/src/main/java/brooklyn/entity/rebind/InitialFullRebindIteration.java index 02cc9e890d..6eb0947887 100644 --- a/core/src/main/java/brooklyn/entity/rebind/InitialFullRebindIteration.java +++ b/core/src/main/java/brooklyn/entity/rebind/InitialFullRebindIteration.java @@ -18,6 +18,7 @@ */ package brooklyn.entity.rebind; +import java.io.IOException; import java.util.Set; import java.util.concurrent.Semaphore; import java.util.concurrent.atomic.AtomicInteger; @@ -70,11 +71,25 @@ protected void doRun() throws Exception { } @Override - protected void loadManifestFiles() throws Exception { + protected void loadRawMementos() { checkEnteringPhase(1); Preconditions.checkState(mementoRawData==null, "Memento raw data should not yet be set when calling this"); mementoRawData = persistenceStoreAccess.loadMementoRawData(exceptionHandler); - + } + + @Override + protected void instantiateCatalogMementos() { + checkEnteringPhase(2); + Preconditions.checkState(mementoRawData!=null, "Memento raw data should be set when calling this"); + Preconditions.checkState(mementoCatalogManifest==null, "Catalog mementos should not be loaded when calling this"); + + mementoCatalogManifest = persistenceStoreAccess.loadCatalogMementos(mementoRawData, exceptionHandler); + } + + @Override + protected void loadMementoManifest() throws Exception { + checkEnteringPhase(4); + preprocessManifestFiles(); if (!isEmpty) { diff --git a/core/src/main/java/brooklyn/entity/rebind/RebindIteration.java b/core/src/main/java/brooklyn/entity/rebind/RebindIteration.java index 89c125a472..f360fa0723 100644 --- a/core/src/main/java/brooklyn/entity/rebind/RebindIteration.java +++ b/core/src/main/java/brooklyn/entity/rebind/RebindIteration.java @@ -25,6 +25,7 @@ import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.Semaphore; import java.util.concurrent.atomic.AtomicBoolean; @@ -55,6 +56,7 @@ import brooklyn.entity.proxying.InternalPolicyFactory; import brooklyn.entity.rebind.RebindManagerImpl.RebindTracker; import brooklyn.entity.rebind.persister.PersistenceActivityMetrics; +import brooklyn.entity.rebind.transformer.RawDataTransformer; import brooklyn.event.feed.AbstractFeed; import brooklyn.internal.BrooklynFeatureEnablement; import brooklyn.location.Location; @@ -68,9 +70,10 @@ import brooklyn.management.internal.LocationManagerInternal; import brooklyn.management.internal.ManagementContextInternal; import brooklyn.management.internal.ManagementTransitionMode; +import brooklyn.mementos.BrooklynCatalogMementoManifest; import brooklyn.mementos.BrooklynMemento; import brooklyn.mementos.BrooklynMementoManifest; -import brooklyn.mementos.BrooklynMementoManifest.EntityMementoManifest; +import brooklyn.mementos.BrooklynMementoManifest.MementoManifest; import brooklyn.mementos.BrooklynMementoPersister; import brooklyn.mementos.BrooklynMementoRawData; import brooklyn.mementos.CatalogItemMemento; @@ -108,15 +111,19 @@
  • 1. load the manifest files and populate the summaries (ID+type) in {@link BrooklynMementoManifest}
  • 2. instantiate and reconstruct catalog items -
  • 3. instantiate entities+locations -- so that inter-entity references can subsequently +
  • 3. Apply global transformers on raw manifest +
  • 4. load manifest +
  • 5. Apply per-blueprint transformers +
  • 6. Reload manifest because of above changes +
  • 7. instantiate entities+locations -- so that inter-entity references can subsequently be set during deserialize (and entity config/state is set). -
  • 4. deserialize the manifests to instantiate the mementos -
  • 5. instantiate policies+enrichers+feeds +
  • 8. deserialize the manifests to instantiate the mementos +
  • 9. instantiate policies+enrichers+feeds (could probably merge this with (3), depending how they are implemented) -
  • 6. reconstruct the locations, policies, etc, then finally entities -- setting all fields and then calling +
  • 10. reconstruct the locations, policies, etc, then finally entities -- setting all fields and then calling {@link RebindSupport#reconstruct(RebindContext, Memento)} -
  • 7. associate policies+enrichers+feeds to all the entities -
  • 8. manage the entities +
  • 11. associate policies+enrichers+feeds to all the entities +
  • 12. manage the entities
If underlying data-store is changed between first and second manifest read (e.g. to add an @@ -175,6 +182,7 @@ public abstract class RebindIteration { // set in first phase protected BrooklynMementoRawData mementoRawData; + protected BrooklynCatalogMementoManifest mementoCatalogManifest; protected BrooklynMementoManifest mementoManifest; protected Boolean overwritingMaster; protected Boolean isEmpty; @@ -227,8 +235,13 @@ RebindContextImpl getRebindContext() { } protected void doRun() throws Exception { - loadManifestFiles(); + loadRawMementos(); + instantiateCatalogMementos(); rebuildCatalog(); + applyGlobalTransformers(); + loadMementoManifest(); + applyBlueprintTransformers(); + reloadManifestFiles(); instantiateLocationsAndEntities(); instantiateMementos(); instantiateAdjuncts(instantiator); @@ -238,8 +251,12 @@ protected void doRun() throws Exception { finishingUp(); } - protected abstract void loadManifestFiles() throws Exception; - + protected abstract void loadRawMementos(); + + protected abstract void instantiateCatalogMementos(); + + protected abstract void loadMementoManifest() throws Exception; + public void run() { if (iterationStarted.getAndSet(true)) { throw new IllegalStateException("Iteration "+this+" has already run; create a new instance for another rebind pass."); @@ -285,29 +302,42 @@ protected void checkContinuingPhase(int targetPhase) { } protected void preprocessManifestFiles() throws Exception { - checkContinuingPhase(1); + checkContinuingPhase(4); Preconditions.checkState(mementoRawData!=null, "Memento raw data should be set when calling this"); Preconditions.checkState(mementoManifest==null, "Memento data should not yet be set when calling this"); - // TODO building the manifests should be part of this class (or parent) - // it does not have anything to do with the persistence store! - mementoManifest = persistenceStoreAccess.loadMementoManifest(mementoRawData, exceptionHandler); + loadManifestFiles(); overwritingMaster = false; isEmpty = mementoManifest.isEmpty(); } + protected void reloadManifestFiles() throws IOException { + checkEnteringPhase(6); + loadManifestFiles(); + } + + protected void loadManifestFiles() throws IOException { + //Called twice in the lifecycle to reload changes + if (phase != 4 && phase != 6) + throw new IllegalStateException("Phase mismatch: should be phase 4 or 6 but is currently "+phase); + + // TODO building the manifests should be part of this class (or parent) + // it does not have anything to do with the persistence store! + mementoManifest = persistenceStoreAccess.loadMementoManifest(mementoRawData, exceptionHandler); + } + @SuppressWarnings("deprecation") protected void rebuildCatalog() { // Build catalog early so we can load other things - checkEnteringPhase(2); + checkContinuingPhase(2); // Instantiate catalog items if (rebindManager.persistCatalogItemsEnabled) { - logRebindingDebug("RebindManager instantiating catalog items: {}", mementoManifest.getCatalogItemIds()); - for (CatalogItemMemento catalogItemMemento : mementoManifest.getCatalogItemMementos().values()) { + logRebindingDebug("RebindManager instantiating catalog items: {}", mementoCatalogManifest.getCatalogItemIds()); + for (CatalogItemMemento catalogItemMemento : mementoCatalogManifest.getCatalogItemMementos().values()) { logRebindingDebug("RebindManager instantiating catalog item {}", catalogItemMemento); try { CatalogItem catalogItem = instantiator.newCatalogItem(catalogItemMemento); @@ -317,13 +347,13 @@ protected void rebuildCatalog() { } } } else { - logRebindingDebug("Not rebinding catalog; feature disabled: {}", mementoManifest.getCatalogItemIds()); + logRebindingDebug("Not rebinding catalog; feature disabled: {}", mementoCatalogManifest.getCatalogItemIds()); } // Reconstruct catalog entries if (rebindManager.persistCatalogItemsEnabled) { logRebindingDebug("RebindManager reconstructing catalog items"); - for (CatalogItemMemento catalogItemMemento : mementoManifest.getCatalogItemMementos().values()) { + for (CatalogItemMemento catalogItemMemento : mementoCatalogManifest.getCatalogItemMementos().values()) { CatalogItem item = rebindContext.getCatalogItem(catalogItemMemento.getId()); logRebindingDebug("RebindManager reconstructing catalog item {}", catalogItemMemento); if (item == null) { @@ -381,7 +411,7 @@ protected void rebuildCatalog() { needsInitialItemsLoaded = true; needsAdditionalItemsLoaded = true; } else { - if (!isEmpty) { + if (!mementoRawData.isEmpty()) { logRebindingDebug("RebindManager clearing local catalog and loading from persisted state"); itemsForResettingCatalog = rebindContext.getCatalogItems(); needsInitialItemsLoaded = false; @@ -416,14 +446,13 @@ protected void rebuildCatalog() { } protected void instantiateLocationsAndEntities() { - - checkEnteringPhase(3); + checkEnteringPhase(7); // Instantiate locations - logRebindingDebug("RebindManager instantiating locations: {}", mementoManifest.getLocationIdToType().keySet()); - for (Map.Entry entry : mementoManifest.getLocationIdToType().entrySet()) { + logRebindingDebug("RebindManager instantiating locations: {}", mementoManifest.getLocationIdToManifest().keySet()); + for (Map.Entry entry : mementoManifest.getLocationIdToManifest().entrySet()) { String locId = entry.getKey(); - String locType = entry.getValue(); + String locType = entry.getValue().getType(); if (LOG.isTraceEnabled()) LOG.trace("RebindManager instantiating location {}", locId); try { @@ -436,9 +465,9 @@ protected void instantiateLocationsAndEntities() { // Instantiate entities logRebindingDebug("RebindManager instantiating entities: {}", mementoManifest.getEntityIdToManifest().keySet()); - for (Map.Entry entry : mementoManifest.getEntityIdToManifest().entrySet()) { + for (Map.Entry entry : mementoManifest.getEntityIdToManifest().entrySet()) { String entityId = entry.getKey(); - EntityMementoManifest entityManifest = entry.getValue(); + MementoManifest entityManifest = entry.getValue(); if (LOG.isTraceEnabled()) LOG.trace("RebindManager instantiating entity {}", entityId); @@ -454,15 +483,14 @@ protected void instantiateLocationsAndEntities() { } protected void instantiateMementos() throws IOException { - - checkEnteringPhase(4); - + checkEnteringPhase(8); + memento = persistenceStoreAccess.loadMemento(mementoRawData, rebindContext.lookup(), exceptionHandler); } protected void instantiateAdjuncts(BrooklynObjectInstantiator instantiator) { - checkEnteringPhase(5); + checkEnteringPhase(9); // Instantiate policies if (rebindManager.persistPoliciesEnabled) { @@ -518,7 +546,7 @@ protected void instantiateAdjuncts(BrooklynObjectInstantiator instantiator) { protected void reconstructEverything() { - checkEnteringPhase(6); + checkEnteringPhase(10); // Reconstruct locations logRebindingDebug("RebindManager reconstructing locations"); @@ -623,7 +651,7 @@ protected void reconstructEverything() { protected void associateAdjunctsWithEntities() { - checkEnteringPhase(7); + checkEnteringPhase(11); logRebindingDebug("RebindManager associating adjuncts to entities"); for (EntityMemento entityMemento : sortParentFirst(memento.getEntityMementos()).values()) { @@ -650,7 +678,7 @@ protected void associateAdjunctsWithEntities() { protected void manageTheObjects() { - checkEnteringPhase(8); + checkEnteringPhase(12); logRebindingDebug("RebindManager managing locations"); LocationManagerInternal locationManager = (LocationManagerInternal)managementContext.getLocationManager(); @@ -740,7 +768,7 @@ protected Collection getMementoRootEntities() { protected void finishingUp() { - checkContinuingPhase(8); + checkContinuingPhase(12); if (!isEmpty) { BrooklynLogging.log(LOG, shouldLogRebinding() ? LoggingLevel.INFO : LoggingLevel.DEBUG, @@ -772,14 +800,14 @@ protected void noteErrors(final RebindExceptionHandler exceptionHandler, Excepti } } - protected String findCatalogItemId(ClassLoader cl, Map entityIdToManifest, EntityMementoManifest entityManifest) { + protected String findCatalogItemId(ClassLoader cl, Map entityIdToManifest, MementoManifest entityManifest) { if (entityManifest.getCatalogItemId() != null) { return entityManifest.getCatalogItemId(); } if (BrooklynFeatureEnablement.isEnabled(BrooklynFeatureEnablement.FEATURE_BACKWARDS_COMPATIBILITY_INFER_CATALOG_ITEM_ON_REBIND)) { //First check if any of the parent entities has a catalogItemId set. - EntityMementoManifest ptr = entityManifest; + MementoManifest ptr = entityManifest; while (ptr != null) { if (ptr.getCatalogItemId() != null) { CatalogItem catalogItem = CatalogUtils.getCatalogItemOptionalVersion(managementContext, ptr.getCatalogItemId()); @@ -859,7 +887,7 @@ protected BrooklynObjectInstantiator(ClassLoader classLoader, RebindContextImpl this.reflections = reflections; } - protected Entity newEntity(EntityMementoManifest entityManifest) { + protected Entity newEntity(MementoManifest entityManifest) { String entityId = entityManifest.getId(); String catalogItemId = findCatalogItemId(classLoader, mementoManifest.getEntityIdToManifest(), entityManifest); String entityType = entityManifest.getType(); @@ -1155,4 +1183,57 @@ protected boolean shouldLogRebinding() { return (readOnlyRebindCount.get() < 5) || (readOnlyRebindCount.get()%1000==0); } + private void applyGlobalTransformers() { + checkEnteringPhase(3); + + Iterable globalTransformers = new TransformerLoader(managementContext).findGlobalTransformers(); + BrooklynMementoRawData.Builder rawBuilder = BrooklynMementoRawData.builder(); + for (BrooklynObjectType type : BrooklynObjectType.values()) { + if (type == BrooklynObjectType.UNKNOWN) continue; + Map objs = mementoRawData.getObjectsOfType(type); + for (Entry entry: objs.entrySet()) { + String contents = entry.getValue(); + for (RawDataTransformer transformer : globalTransformers) { + try { + contents = transformer.transform(contents); + } catch (Exception e) { + LOG.warn("Transformer " + transformer + " failed while working on " + entry.getKey(), e); + } + } + rawBuilder.put(type, entry.getKey(), contents); + } + } + mementoRawData = rawBuilder.build(); + } + + protected void applyBlueprintTransformers() { + checkEnteringPhase(5); + + BrooklynMementoRawData.Builder rawBuilder = BrooklynMementoRawData.builder(); + applyBlueprintTransformers(BrooklynObjectType.ENTITY, mementoManifest.getEntityIdToManifest(), rawBuilder); + applyBlueprintTransformers(BrooklynObjectType.POLICY, mementoManifest.getPolicyIdToManifest(), rawBuilder); + applyBlueprintTransformers(BrooklynObjectType.ENRICHER, mementoManifest.getEnricherIdToManifest(), rawBuilder); + applyBlueprintTransformers(BrooklynObjectType.FEED, mementoManifest.getFeedIdToManifest(), rawBuilder); + applyBlueprintTransformers(BrooklynObjectType.LOCATION, mementoManifest.getLocationIdToManifest(), rawBuilder); + mementoRawData = rawBuilder.build(); + } + + protected void applyBlueprintTransformers(BrooklynObjectType brooklynObjectType, Map brooklynObjectIdToManifest, BrooklynMementoRawData.Builder rawBuilder) { + Map objs = mementoRawData.getObjectsOfType(brooklynObjectType); + TransformerLoader transformerLoader = new TransformerLoader(managementContext); + for (MementoManifest manifest : brooklynObjectIdToManifest.values()) { + String id = manifest.getId(); + Iterable blueprintTransformers = transformerLoader.findBlueprintTransformers(manifest); + String contents = objs.get(id); + for (RawDataTransformer transformer : blueprintTransformers) { + try { + contents = transformer.transform(contents); + } catch (Exception e) { + LOG.warn("Transformer " + transformer + " failed while working on " + id, e); + } + } + rawBuilder.put(brooklynObjectType, id, contents); + } + } + } diff --git a/core/src/main/java/brooklyn/entity/rebind/TransformerLoader.java b/core/src/main/java/brooklyn/entity/rebind/TransformerLoader.java new file mode 100644 index 0000000000..ce9a910379 --- /dev/null +++ b/core/src/main/java/brooklyn/entity/rebind/TransformerLoader.java @@ -0,0 +1,141 @@ +/* + * 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 brooklyn.entity.rebind; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.ServiceLoader; + +import org.osgi.framework.Bundle; +import org.osgi.framework.launch.Framework; +import org.osgi.framework.wiring.BundleWiring; + +import brooklyn.catalog.CatalogItem; +import brooklyn.catalog.internal.CatalogUtils; +import brooklyn.entity.rebind.transformer.RawDataTransformer; +import brooklyn.entity.rebind.transformer.TransformedBy; +import brooklyn.management.classloading.BrooklynClassLoadingContext; +import brooklyn.management.classloading.JavaBrooklynClassLoadingContext; +import brooklyn.management.ha.OsgiManager; +import brooklyn.management.internal.ManagementContextInternal; +import brooklyn.mementos.BrooklynMementoManifest.MementoManifest; +import brooklyn.util.exceptions.Exceptions; +import brooklyn.util.guava.Maybe; +import brooklyn.util.osgi.Osgis; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; + +public class TransformerLoader { + private static final String TRANSFORMER_SUFFIX = "Transformer"; + + private ManagementContextInternal managementContext; + + public TransformerLoader(ManagementContextInternal managementContext) { + this.managementContext = managementContext; + } + + public Collection findGlobalTransformers() { + Collection allTransformers = new ArrayList(); + Iterables.addAll(allTransformers, ServiceLoader.load(RawDataTransformer.class, managementContext.getCatalog().getRootClassLoader())); + Maybe osgiManager = managementContext.getOsgiManager(); + if (osgiManager.isPresent()) { + Framework framework = osgiManager.get().getFramework(); + Bundle[] bundles = framework.getBundleContext().getBundles(); + for (Bundle bundle : bundles) { + if (bundle == framework) continue; + if (Osgis.isExtensionBundle(bundle)) continue; + + try { + //TODO better .start the bundle on install + bundle.loadClass("Some.None.Existent.Class.To.Force.BundleWiring.Initialization"); + } catch (ClassNotFoundException e1) {} + BundleWiring bundleWiring = bundle.adapt(BundleWiring.class); + if (bundleWiring == null) continue; //bundle not resolved + ClassLoader bundleClassLoader = bundleWiring.getClassLoader(); + try { + ServiceLoader bundleTransformers = ServiceLoader.load(RawDataTransformer.class, bundleClassLoader); + Iterables.addAll(allTransformers, bundleTransformers); + } catch (Throwable e) { + Exceptions.propagateIfFatal(e); + //LOG.debug(e); + } + } + } + return allTransformers; + } + + public Collection findBlueprintTransformers(MementoManifest manifest) { + BrooklynClassLoadingContext loader = getLoader(manifest); + RawDataTransformer transformer = getTransformerInstance(manifest.getType(), loader); + if (transformer != null) { + return ImmutableList.of(transformer); + } else { + return ImmutableList.of(); + } + } + + private RawDataTransformer getTransformerInstance(String type, BrooklynClassLoadingContext loader) { + Class transformerType = getTransformerType(type, loader); + if (transformerType != null) { + try { + return transformerType.newInstance(); + } catch (Exception e) { + return null; + } + } else { + return null; + } + } + + private Class getTransformerType(String type, BrooklynClassLoadingContext loader) { + Class cls; + try { + cls = loader.loadClass(type); + } catch (Throwable e) { + Exceptions.propagateIfFatal(e); + return null; + } + TransformedBy transformedBy = cls.getAnnotation(TransformedBy.class); + if (transformedBy != null) { + return transformedBy.value(); + } else { + try { + @SuppressWarnings("unchecked") + Class transformerClass = (Class) loader.loadClass(type + TRANSFORMER_SUFFIX); + return transformerClass; + } catch (Throwable e) { + Exceptions.propagateIfFatal(e); + return null; + } + } + } + + private BrooklynClassLoadingContext getLoader(MementoManifest manifest) { + String catalogItemId = manifest.getCatalogItemId(); + if (catalogItemId != null) { + CatalogItem item = CatalogUtils.getCatalogItemOptionalVersion(managementContext, catalogItemId); + if (item != null) { + return CatalogUtils.newClassLoadingContext(managementContext, item); + } + } + return JavaBrooklynClassLoadingContext.create(managementContext); + } + +} diff --git a/core/src/main/java/brooklyn/entity/rebind/dto/BasicCatalogMementoManifest.java b/core/src/main/java/brooklyn/entity/rebind/dto/BasicCatalogMementoManifest.java new file mode 100644 index 0000000000..2ceafa4d4c --- /dev/null +++ b/core/src/main/java/brooklyn/entity/rebind/dto/BasicCatalogMementoManifest.java @@ -0,0 +1,71 @@ +/* + * 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 brooklyn.entity.rebind.dto; + +import java.util.Collection; +import java.util.Collections; +import java.util.Map; + +import brooklyn.mementos.BrooklynCatalogMementoManifest; +import brooklyn.mementos.CatalogItemMemento; + +import com.google.common.collect.Maps; + +public class BasicCatalogMementoManifest implements BrooklynCatalogMementoManifest { + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + protected final Map catalogItems = Maps.newConcurrentMap(); + public Builder catalogItem(CatalogItemMemento val) { + catalogItems.put(val.getId(), val); return this; + } + public BasicCatalogMementoManifest build() { + return new BasicCatalogMementoManifest(catalogItems); + } + } + + private Map mementos; + + private BasicCatalogMementoManifest(Map mementos) { + this.mementos = mementos; + } + + @Override + public CatalogItemMemento getCatalogItemMemento(String id) { + return mementos.get(id); + } + + @Override + public Collection getCatalogItemIds() { + return Collections.unmodifiableSet(mementos.keySet()); + } + + @Override + public Map getCatalogItemMementos() { + return Collections.unmodifiableMap(mementos); + } + + @Override + public boolean isEmpty() { + return mementos.isEmpty(); + } + +} diff --git a/core/src/main/java/brooklyn/entity/rebind/dto/BrooklynMementoManifestImpl.java b/core/src/main/java/brooklyn/entity/rebind/dto/BrooklynMementoManifestImpl.java index 485030915d..b5bc597ee2 100644 --- a/core/src/main/java/brooklyn/entity/rebind/dto/BrooklynMementoManifestImpl.java +++ b/core/src/main/java/brooklyn/entity/rebind/dto/BrooklynMementoManifestImpl.java @@ -39,42 +39,42 @@ public static Builder builder() { public static class Builder { protected String brooklynVersion; - protected final Map entityIdToManifest = Maps.newConcurrentMap(); - protected final Map locationIdToType = Maps.newConcurrentMap(); - protected final Map policyIdToType = Maps.newConcurrentMap(); - protected final Map enricherIdToType = Maps.newConcurrentMap(); - protected final Map feedIdToType = Maps.newConcurrentMap(); + protected final Map entityIdToManifest = Maps.newConcurrentMap(); + protected final Map locationIdToType = Maps.newConcurrentMap(); + protected final Map policyIdToType = Maps.newConcurrentMap(); + protected final Map enricherIdToType = Maps.newConcurrentMap(); + protected final Map feedIdToType = Maps.newConcurrentMap(); protected final Map catalogItems = Maps.newConcurrentMap(); public Builder brooklynVersion(String val) { brooklynVersion = val; return this; } public Builder entity(String id, String type, String parent, String catalogItemId) { - entityIdToManifest.put(id, new EntityMementoManifestImpl(id, type, parent, catalogItemId)); + entityIdToManifest.put(id, new MementoManifestImpl(id, type, parent, catalogItemId)); return this; } - public Builder location(String id, String type) { - locationIdToType.put(id, type); return this; + public Builder location(String id, String type, String catalogItemId) { + locationIdToType.put(id, new MementoManifestImpl(id, type, null, catalogItemId)); return this; } - public Builder locations(Map vals) { + public Builder locations(Map vals) { locationIdToType.putAll(vals); return this; } - public Builder policy(String id, String type) { - policyIdToType.put(id, type); return this; + public Builder policy(String id, String type, String catalogItemId) { + policyIdToType.put(id, new MementoManifestImpl(id, type, null, catalogItemId)); return this; } - public Builder policies(Map vals) { + public Builder policies(Map vals) { policyIdToType.putAll(vals); return this; } - public Builder enricher(String id, String type) { - enricherIdToType.put(id, type); return this; + public Builder enricher(String id, String type, String catalogItemId) { + enricherIdToType.put(id, new MementoManifestImpl(id, type, null, catalogItemId)); return this; } - public Builder enrichers(Map vals) { + public Builder enrichers(Map vals) { enricherIdToType.putAll(vals); return this; } - public Builder feed(String id, String type) { - feedIdToType.put(id, type); return this; + public Builder feed(String id, String type, String catalogItemId) { + feedIdToType.put(id, new MementoManifestImpl(id, type, null, catalogItemId)); return this; } - public Builder feed(Map vals) { + public Builder feed(Map vals) { feedIdToType.putAll(vals); return this; } public Builder catalogItems(Map vals) { @@ -84,13 +84,13 @@ public Builder catalogItem(CatalogItemMemento val) { catalogItems.put(val.getId(), val); return this; } - public Builder putType(BrooklynObjectType type, String id, String javaType) { + public Builder putType(BrooklynObjectType type, String id, String javaType, String catalogItemId) { switch (type) { case ENTITY: throw new IllegalArgumentException(type.toCamelCase()+" requires additional parameters"); - case LOCATION: return location(id, javaType); - case POLICY: return policy(id, javaType); - case ENRICHER: return enricher(id, javaType); - case FEED: return feed(id, javaType); + case LOCATION: return location(id, javaType, catalogItemId); + case POLICY: return policy(id, javaType, catalogItemId); + case ENRICHER: return enricher(id, javaType, catalogItemId); + case FEED: return feed(id, javaType, catalogItemId); case CATALOG_ITEM: throw new IllegalArgumentException(type.toCamelCase()+" requires different parameters"); case UNKNOWN: default: @@ -103,45 +103,45 @@ public BrooklynMementoManifest build() { } } - private final Map entityIdToManifest; - private final Map locationIdToType; - private final Map policyIdToType; - private final Map enricherIdToType; - private final Map feedIdToType; + private final Map entityIdToManifest; + private final Map locationIdToManifest; + private final Map policyIdToManifest; + private final Map enricherIdToManifest; + private final Map feedIdToManifest; private Map catalogItems; private BrooklynMementoManifestImpl(Builder builder) { entityIdToManifest = builder.entityIdToManifest; - locationIdToType = builder.locationIdToType; - policyIdToType = builder.policyIdToType; - enricherIdToType = builder.enricherIdToType; - feedIdToType = builder.feedIdToType; + locationIdToManifest = builder.locationIdToType; + policyIdToManifest = builder.policyIdToType; + enricherIdToManifest = builder.enricherIdToType; + feedIdToManifest = builder.feedIdToType; catalogItems = builder.catalogItems; } @Override - public Map getEntityIdToManifest() { + public Map getEntityIdToManifest() { return Collections.unmodifiableMap(entityIdToManifest); } @Override - public Map getLocationIdToType() { - return Collections.unmodifiableMap(locationIdToType); + public Map getLocationIdToManifest() { + return Collections.unmodifiableMap(locationIdToManifest); } @Override - public Map getPolicyIdToType() { - return Collections.unmodifiableMap(policyIdToType); + public Map getPolicyIdToManifest() { + return Collections.unmodifiableMap(policyIdToManifest); } @Override - public Map getEnricherIdToType() { - return Collections.unmodifiableMap(enricherIdToType); + public Map getEnricherIdToManifest() { + return Collections.unmodifiableMap(enricherIdToManifest); } @Override - public Map getFeedIdToType() { - return Collections.unmodifiableMap(feedIdToType); + public Map getFeedIdToManifest() { + return Collections.unmodifiableMap(feedIdToManifest); } @Override @@ -162,10 +162,10 @@ public Map getCatalogItemMementos() { @Override public boolean isEmpty() { return entityIdToManifest.isEmpty() && - locationIdToType.isEmpty() && - policyIdToType.isEmpty() && - enricherIdToType.isEmpty() && - feedIdToType.isEmpty() && + locationIdToManifest.isEmpty() && + policyIdToManifest.isEmpty() && + enricherIdToManifest.isEmpty() && + feedIdToManifest.isEmpty() && catalogItems.isEmpty(); } diff --git a/core/src/main/java/brooklyn/entity/rebind/dto/EntityMementoManifestImpl.java b/core/src/main/java/brooklyn/entity/rebind/dto/MementoManifestImpl.java similarity index 84% rename from core/src/main/java/brooklyn/entity/rebind/dto/EntityMementoManifestImpl.java rename to core/src/main/java/brooklyn/entity/rebind/dto/MementoManifestImpl.java index 05b1dd7c76..1ec51dc1a4 100644 --- a/core/src/main/java/brooklyn/entity/rebind/dto/EntityMementoManifestImpl.java +++ b/core/src/main/java/brooklyn/entity/rebind/dto/MementoManifestImpl.java @@ -18,15 +18,15 @@ */ package brooklyn.entity.rebind.dto; -import brooklyn.mementos.BrooklynMementoManifest.EntityMementoManifest; +import brooklyn.mementos.BrooklynMementoManifest.MementoManifest; -public class EntityMementoManifestImpl implements EntityMementoManifest { +public class MementoManifestImpl implements MementoManifest { private String id; private String type; private String parentId; private String catalogItemId; - public EntityMementoManifestImpl(String id, String type, String parentId, String catalogItemId) { + public MementoManifestImpl(String id, String type, String parentId, String catalogItemId) { this.id = id; this.type = type; this.parentId = parentId; diff --git a/core/src/main/java/brooklyn/entity/rebind/persister/AbstractBrooklynMementoPersister.java b/core/src/main/java/brooklyn/entity/rebind/persister/AbstractBrooklynMementoPersister.java index d3f85df18c..31b31af369 100644 --- a/core/src/main/java/brooklyn/entity/rebind/persister/AbstractBrooklynMementoPersister.java +++ b/core/src/main/java/brooklyn/entity/rebind/persister/AbstractBrooklynMementoPersister.java @@ -25,8 +25,10 @@ import brooklyn.entity.rebind.PersistenceExceptionHandler; import brooklyn.entity.rebind.RebindExceptionHandler; +import brooklyn.entity.rebind.dto.BasicCatalogMementoManifest; import brooklyn.entity.rebind.dto.BrooklynMementoManifestImpl; import brooklyn.entity.rebind.dto.MutableBrooklynMemento; +import brooklyn.mementos.BrooklynCatalogMementoManifest; import brooklyn.mementos.BrooklynMemento; import brooklyn.mementos.BrooklynMementoManifest; import brooklyn.mementos.BrooklynMementoPersister; @@ -68,20 +70,29 @@ public BrooklynMementoManifest loadMementoManifest(RebindExceptionHandler except return loadMementoManifest(null, exceptionHandler); } + @Override + public BrooklynCatalogMementoManifest loadCatalogMementos(BrooklynMementoRawData mementoData, RebindExceptionHandler exceptionHandler) { + BasicCatalogMementoManifest.Builder builder = BasicCatalogMementoManifest.builder(); + for (CatalogItemMemento entity : memento.getCatalogItemMementos().values()) { + builder.catalogItem(entity); + } + return builder.build(); + } + @Override public BrooklynMementoManifest loadMementoManifest(BrooklynMementoRawData mementoData, RebindExceptionHandler exceptionHandler) { BrooklynMementoManifestImpl.Builder builder = BrooklynMementoManifestImpl.builder(); for (EntityMemento entity : memento.getEntityMementos().values()) { builder.entity(entity.getId(), entity.getType(), entity.getParent(), entity.getCatalogItemId()); } - for (LocationMemento entity : memento.getLocationMementos().values()) { - builder.location(entity.getId(), entity.getType()); + for (LocationMemento location : memento.getLocationMementos().values()) { + builder.location(location.getId(), location.getType(), location.getCatalogItemId()); } - for (PolicyMemento entity : memento.getPolicyMementos().values()) { - builder.policy(entity.getId(), entity.getType()); + for (PolicyMemento policy : memento.getPolicyMementos().values()) { + builder.policy(policy.getId(), policy.getType(), policy.getCatalogItemId()); } - for (EnricherMemento entity : memento.getEnricherMementos().values()) { - builder.enricher(entity.getId(), entity.getType()); + for (EnricherMemento enricher : memento.getEnricherMementos().values()) { + builder.enricher(enricher.getId(), enricher.getType(), enricher.getCatalogItemId()); } for (CatalogItemMemento entity : memento.getCatalogItemMementos().values()) { builder.catalogItem(entity); @@ -98,6 +109,7 @@ public void checkpoint(BrooklynMemento newMemento, PersistenceExceptionHandler e memento.reset(checkNotNull(newMemento, "memento")); } + @Override public void checkpoint(BrooklynMementoRawData newMemento, PersistenceExceptionHandler exceptionHandler) { throw new IllegalStateException("Not supported; use "+BrooklynMementoPersisterToObjectStore.class); } diff --git a/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterInMemory.java b/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterInMemory.java index dbb1e523b3..719d16f1ec 100644 --- a/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterInMemory.java +++ b/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterInMemory.java @@ -42,8 +42,10 @@ import brooklyn.entity.rebind.RebindManager; import brooklyn.location.Location; import brooklyn.management.ManagementContext; +import brooklyn.mementos.BrooklynCatalogMementoManifest; import brooklyn.mementos.BrooklynMemento; import brooklyn.mementos.BrooklynMementoManifest; +import brooklyn.mementos.BrooklynMementoRawData; import brooklyn.policy.Enricher; import brooklyn.policy.Policy; import brooklyn.util.collections.MutableList; @@ -139,19 +141,19 @@ public ManagementContext lookupManagementContext() { }); } @Override public Location lookupLocation(String id) { - Class clazz = loadClass(manifest.getLocationIdToType().get(id)); + Class clazz = loadClass(manifest.getLocationIdToManifest().get(id).getType()); return (Location) invokeConstructor(clazz, new Object[0], new Object[] {MutableMap.of()}); } @Override public Policy lookupPolicy(String id) { - Class clazz = loadClass(manifest.getPolicyIdToType().get(id)); + Class clazz = loadClass(manifest.getPolicyIdToManifest().get(id).getType()); return (Policy) invokeConstructor(clazz, new Object[0], new Object[] {MutableMap.of()}); } @Override public Enricher lookupEnricher(String id) { - Class clazz = loadClass(manifest.getEnricherIdToType().get(id)); + Class clazz = loadClass(manifest.getEnricherIdToManifest().get(id).getType()); return (Enricher) invokeConstructor(clazz, new Object[0], new Object[] {MutableMap.of()}); } @Override public Feed lookupFeed(String id) { - Class clazz = loadClass(manifest.getFeedIdToType().get(id)); + Class clazz = loadClass(manifest.getFeedIdToManifest().get(id).getType()); return (Feed) invokeConstructor(clazz, new Object[0], new Object[] {MutableMap.of()}); } @Override public CatalogItem lookupCatalogItem(String id) { @@ -208,4 +210,12 @@ private T invokeConstructor(Class clazz, Object[]... possibleArgs) { throw Throwables.propagate(e); } } + + @Override + public BrooklynCatalogMementoManifest loadCatalogMementos( + BrooklynMementoRawData mementoData, + RebindExceptionHandler exceptionHandler) { + // TODO Auto-generated method stub + return null; + } } diff --git a/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterToFile.java b/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterToFile.java index 68dd6ebf7b..c591c2f954 100644 --- a/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterToFile.java +++ b/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterToFile.java @@ -144,4 +144,5 @@ private void writeMemento() { LOG.error("Failed to persist memento", e); } } + } diff --git a/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterToMultiFile.java b/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterToMultiFile.java index afb3d61b9e..c1dc22647b 100644 --- a/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterToMultiFile.java +++ b/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterToMultiFile.java @@ -37,6 +37,7 @@ import brooklyn.entity.rebind.RebindExceptionHandler; import brooklyn.entity.rebind.dto.BrooklynMementoImpl; import brooklyn.entity.rebind.dto.BrooklynMementoManifestImpl; +import brooklyn.mementos.BrooklynCatalogMementoManifest; import brooklyn.mementos.BrooklynMemento; import brooklyn.mementos.BrooklynMementoManifest; import brooklyn.mementos.BrooklynMementoPersister; @@ -216,7 +217,8 @@ public BrooklynMementoManifest loadMementoManifest(BrooklynMementoRawData mement String contents = readFile(file); String id = (String) XmlUtil.xpath(contents, "/location/id"); String type = (String) XmlUtil.xpath(contents, "/location/type"); - builder.location(id, type); + String catalogItemId = (String) XmlUtil.xpath(contents, "/entity/catalogItemId"); + builder.location(id, type, Strings.emptyToNull(catalogItemId)); } catch (Exception e) { exceptionHandler.onLoadMementoFailed(BrooklynObjectType.LOCATION, "File "+file, e); } @@ -226,7 +228,8 @@ public BrooklynMementoManifest loadMementoManifest(BrooklynMementoRawData mement String contents = readFile(file); String id = (String) XmlUtil.xpath(contents, "/policy/id"); String type = (String) XmlUtil.xpath(contents, "/policy/type"); - builder.policy(id, type); + String catalogItemId = (String) XmlUtil.xpath(contents, "/entity/catalogItemId"); + builder.policy(id, type, Strings.emptyToNull(catalogItemId)); } catch (Exception e) { exceptionHandler.onLoadMementoFailed(BrooklynObjectType.POLICY, "File "+file, e); } @@ -236,7 +239,8 @@ public BrooklynMementoManifest loadMementoManifest(BrooklynMementoRawData mement String contents = readFile(file); String id = (String) XmlUtil.xpath(contents, "/enricher/id"); String type = (String) XmlUtil.xpath(contents, "/enricher/type"); - builder.enricher(id, type); + String catalogItemId = (String) XmlUtil.xpath(contents, "/entity/catalogItemId"); + builder.enricher(id, type, Strings.emptyToNull(catalogItemId)); } catch (Exception e) { exceptionHandler.onLoadMementoFailed(BrooklynObjectType.ENRICHER, "File "+file, e); } @@ -246,7 +250,8 @@ public BrooklynMementoManifest loadMementoManifest(BrooklynMementoRawData mement String contents = readFile(file); String id = (String) XmlUtil.xpath(contents, "/catalogItem/id"); String type = (String) XmlUtil.xpath(contents, "/catalogItem/type"); - builder.enricher(id, type); + String catalogItemId = (String) XmlUtil.xpath(contents, "/entity/catalogItemId"); + builder.enricher(id, type, Strings.emptyToNull(catalogItemId)); } catch (Exception e) { exceptionHandler.onLoadMementoFailed(BrooklynObjectType.CATALOG_ITEM, "File "+file, e); } @@ -456,6 +461,7 @@ public void waitForWritesCompleted(long timeout, TimeUnit unit) throws Interrupt waitForWritesCompleted(Duration.of(timeout, unit)); } + @Override public void waitForWritesCompleted(Duration timeout) throws InterruptedException, TimeoutException { for (MementoFileWriter writer : entityWriters.values()) { writer.waitForWriteCompleted(timeout); @@ -597,5 +603,13 @@ private File getFileFor(File parent, String id) { public String getBackingStoreDescription() { return toString(); } + + @Override + public BrooklynCatalogMementoManifest loadCatalogMementos( + BrooklynMementoRawData mementoData, + RebindExceptionHandler exceptionHandler) { + // TODO Auto-generated method stub + return null; + } } diff --git a/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterToObjectStore.java b/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterToObjectStore.java index 6e3c24d14c..81d9d27f08 100644 --- a/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterToObjectStore.java +++ b/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterToObjectStore.java @@ -25,6 +25,7 @@ import java.util.List; import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.Map.Entry; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; @@ -49,11 +50,13 @@ import brooklyn.entity.rebind.PersistenceExceptionHandler; import brooklyn.entity.rebind.PersisterDeltaImpl; import brooklyn.entity.rebind.RebindExceptionHandler; +import brooklyn.entity.rebind.dto.BasicCatalogMementoManifest; import brooklyn.entity.rebind.dto.BrooklynMementoImpl; import brooklyn.entity.rebind.dto.BrooklynMementoManifestImpl; import brooklyn.entity.rebind.persister.PersistenceObjectStore.StoreObjectAccessor; import brooklyn.entity.rebind.persister.PersistenceObjectStore.StoreObjectAccessorWithLock; import brooklyn.management.classloading.ClassLoaderFromBrooklynClassLoadingContext; +import brooklyn.mementos.BrooklynCatalogMementoManifest; import brooklyn.mementos.BrooklynMemento; import brooklyn.mementos.BrooklynMementoManifest; import brooklyn.mementos.BrooklynMementoPersister; @@ -279,6 +282,7 @@ protected BrooklynMementoRawData listMementoSubPathsAsData(final RebindException return subPathData; } + @Override public BrooklynMementoRawData loadMementoRawData(final RebindExceptionHandler exceptionHandler) { BrooklynMementoRawData subPathData = listMementoSubPathsAsData(exceptionHandler); @@ -321,6 +325,26 @@ public void visit(BrooklynObjectType type, String id, String contentsSubpath) th return result; } + @Override + public BrooklynCatalogMementoManifest loadCatalogMementos(BrooklynMementoRawData mementoRawData, RebindExceptionHandler exceptionHandler) { + BasicCatalogMementoManifest.Builder builder = BasicCatalogMementoManifest.builder(); + for (Entry catalogItem : mementoRawData.getCatalogItems().entrySet()) { + String id = catalogItem.getKey(); + String contents = catalogItem.getValue(); + try { + CatalogItemMemento memento = (CatalogItemMemento) getSerializerWithStandardClassLoader().fromString(contents); + if (memento == null) { + LOG.warn("No " + BrooklynObjectType.CATALOG_ITEM.toCamelCase() + "-memento deserialized from " + id + "; ignoring and continuing"); + } else { + builder.catalogItem(memento); + } + } catch (Exception e) { + exceptionHandler.onLoadMementoFailed(BrooklynObjectType.CATALOG_ITEM, "memento "+id+" early catalog deserialization error", e); + } + } + return builder.build(); + } + @Override public BrooklynMementoManifest loadMementoManifest(final RebindExceptionHandler exceptionHandler) throws IOException { return loadMementoManifest(null, exceptionHandler); @@ -354,7 +378,7 @@ private String get(String innerPath) { case POLICY: case ENRICHER: case FEED: - builder.putType(type, x.get("id"), x.get("type")); + builder.putType(type, x.get("id"), x.get("type"), Strings.emptyToNull(x.get("catalogItemId"))); break; case CATALOG_ITEM: try { @@ -383,8 +407,8 @@ private String get(String innerPath) { if (LOG.isDebugEnabled()) { LOG.debug("Loaded rebind manifests; took {}: {} entities, {} locations, {} policies, {} enrichers, {} feeds, {} catalog items; from {}", new Object[]{ Time.makeTimeStringRounded(stopwatch), - result.getEntityIdToManifest().size(), result.getLocationIdToType().size(), - result.getPolicyIdToType().size(), result.getEnricherIdToType().size(), result.getFeedIdToType().size(), + result.getEntityIdToManifest().size(), result.getLocationIdToManifest().size(), + result.getPolicyIdToManifest().size(), result.getEnricherIdToManifest().size(), result.getFeedIdToManifest().size(), result.getCatalogItemMementos().size(), objectStore.getSummaryName() }); } @@ -458,6 +482,7 @@ public VisitorWrapper(BrooklynObjectType type, Map.Entry objectId this.type = type; this.objectIdAndData = objectIdAndData; } + @Override public void run() { try { visitor.visit(type, objectIdAndData.getKey(), objectIdAndData.getValue()); @@ -702,6 +727,7 @@ private void delete(String subPath, String id, PersistenceExceptionHandler excep private ListenableFuture asyncPersist(final String subPath, final Memento memento, final PersistenceExceptionHandler exceptionHandler) { return executor.submit(new Runnable() { + @Override public void run() { persist(subPath, memento, exceptionHandler); }}); @@ -709,6 +735,7 @@ public void run() { private ListenableFuture asyncPersist(final String subPath, final BrooklynObjectType type, final String id, final String content, final PersistenceExceptionHandler exceptionHandler) { return executor.submit(new Runnable() { + @Override public void run() { persist(subPath, type, id, content, exceptionHandler); }}); @@ -716,6 +743,7 @@ public void run() { private ListenableFuture asyncDelete(final String subPath, final String id, final PersistenceExceptionHandler exceptionHandler) { return executor.submit(new Runnable() { + @Override public void run() { delete(subPath, id, exceptionHandler); }}); diff --git a/core/src/main/java/brooklyn/entity/rebind/persister/FileBasedObjectStore.java b/core/src/main/java/brooklyn/entity/rebind/persister/FileBasedObjectStore.java index c3ce92a98f..27bb93ee9d 100644 --- a/core/src/main/java/brooklyn/entity/rebind/persister/FileBasedObjectStore.java +++ b/core/src/main/java/brooklyn/entity/rebind/persister/FileBasedObjectStore.java @@ -93,6 +93,7 @@ public File getBaseDir() { return basedir; } + @Override public void prepareForMasterUse() { if (doneFirstContentiousWrite.get()) return; diff --git a/core/src/main/java/brooklyn/entity/rebind/transformer/BrooklynRawMementoTransformer.java b/core/src/main/java/brooklyn/entity/rebind/transformer/BrooklynRawMementoTransformer.java new file mode 100644 index 0000000000..6463c2c3d4 --- /dev/null +++ b/core/src/main/java/brooklyn/entity/rebind/transformer/BrooklynRawMementoTransformer.java @@ -0,0 +1,28 @@ +/* + * 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 brooklyn.entity.rebind.transformer; + +import brooklyn.mementos.BrooklynMemento; + +import com.google.common.annotations.Beta; + +@Beta +public interface BrooklynRawMementoTransformer extends RawDataTransformer { + public BrooklynMemento transform(BrooklynMemento input) throws Exception; +} diff --git a/core/src/main/java/brooklyn/entity/rebind/transformer/CompoundTransformer.java b/core/src/main/java/brooklyn/entity/rebind/transformer/CompoundTransformer.java index 550a80c573..bff8e0d722 100644 --- a/core/src/main/java/brooklyn/entity/rebind/transformer/CompoundTransformer.java +++ b/core/src/main/java/brooklyn/entity/rebind/transformer/CompoundTransformer.java @@ -220,7 +220,7 @@ public BrooklynMementoRawData transform(BrooklynMementoPersisterToObjectStore re return transform(rawData); } - public BrooklynMementoRawData transform(BrooklynMementoRawData rawData) throws Exception { + public BrooklynMementoRawData transform(BrooklynMementoRawData rawData) { Map entities = MutableMap.copyOf(rawData.getEntities()); Map locations = MutableMap.copyOf(rawData.getLocations()); Map policies = MutableMap.copyOf(rawData.getPolicies()); diff --git a/core/src/main/java/brooklyn/entity/rebind/transformer/RawDataTransformer.java b/core/src/main/java/brooklyn/entity/rebind/transformer/RawDataTransformer.java index 196f8a12ef..d2087cf126 100644 --- a/core/src/main/java/brooklyn/entity/rebind/transformer/RawDataTransformer.java +++ b/core/src/main/java/brooklyn/entity/rebind/transformer/RawDataTransformer.java @@ -26,5 +26,5 @@ @Beta public interface RawDataTransformer { - public String transform(String input) throws Exception; + public String transform(String input); } diff --git a/core/src/main/java/brooklyn/entity/rebind/transformer/TransformedBy.java b/core/src/main/java/brooklyn/entity/rebind/transformer/TransformedBy.java new file mode 100644 index 0000000000..9e8104c56a --- /dev/null +++ b/core/src/main/java/brooklyn/entity/rebind/transformer/TransformedBy.java @@ -0,0 +1,34 @@ +/* + * 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 brooklyn.entity.rebind.transformer; + +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +@Retention(RUNTIME) +@Target(TYPE) +public @interface TransformedBy { + public static final int ANY_VERSION = -1; + + Class value(); + int fromVersion() default ANY_VERSION; +} diff --git a/core/src/main/java/brooklyn/entity/rebind/transformer/impl/XsltTransformer.java b/core/src/main/java/brooklyn/entity/rebind/transformer/impl/XsltTransformer.java index 00dfc7f83e..907b59daf1 100644 --- a/core/src/main/java/brooklyn/entity/rebind/transformer/impl/XsltTransformer.java +++ b/core/src/main/java/brooklyn/entity/rebind/transformer/impl/XsltTransformer.java @@ -20,17 +20,15 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.net.URISyntaxException; import javax.xml.transform.Source; import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import brooklyn.entity.rebind.transformer.RawDataTransformer; +import brooklyn.util.exceptions.Exceptions; import com.google.common.annotations.Beta; @@ -45,15 +43,20 @@ public XsltTransformer(String xsltContent) { this.xsltContent = xsltContent; } - public String transform(String input) throws IOException, URISyntaxException, TransformerException { - // stream source is single-use - StreamSource xslt = new StreamSource(new ByteArrayInputStream(xsltContent.getBytes())); - Transformer transformer = factory.newTransformer(xslt); - - Source text = new StreamSource(new ByteArrayInputStream(input.getBytes())); - ByteArrayOutputStream baos = new ByteArrayOutputStream(input.length()); - transformer.transform(text, new StreamResult(baos)); - - return new String(baos.toByteArray()); + @Override + public String transform(String input) { + try { + // stream source is single-use + StreamSource xslt = new StreamSource(new ByteArrayInputStream(xsltContent.getBytes())); + Transformer transformer = factory.newTransformer(xslt); + + Source text = new StreamSource(new ByteArrayInputStream(input.getBytes())); + ByteArrayOutputStream baos = new ByteArrayOutputStream(input.length()); + transformer.transform(text, new StreamResult(baos)); + + return new String(baos.toByteArray()); + } catch (Exception e) { + throw Exceptions.propagate(e); + } } } diff --git a/core/src/test/dependencies/osgi/entities/src/main/java/brooklyn/osgi/tests/TestGlobalOsgiTransformer.java b/core/src/test/dependencies/osgi/entities/src/main/java/brooklyn/osgi/tests/TestGlobalOsgiTransformer.java new file mode 100644 index 0000000000..86eaaae15b --- /dev/null +++ b/core/src/test/dependencies/osgi/entities/src/main/java/brooklyn/osgi/tests/TestGlobalOsgiTransformer.java @@ -0,0 +1,34 @@ +/* + * 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 brooklyn.osgi.tests; + +import brooklyn.entity.rebind.transformer.RawDataTransformer; + +public class TestGlobalOsgiTransformer implements RawDataTransformer { + + @Override + public String transform(String input) { + if ("test".equals(input)) { + return TestGlobalOsgiTransformer.class.getSimpleName(); + } else { + return input; + } + } + +} diff --git a/core/src/test/dependencies/osgi/entities/src/main/java/brooklyn/osgi/tests/transforms/TransformOsgiEntityAnnotated.java b/core/src/test/dependencies/osgi/entities/src/main/java/brooklyn/osgi/tests/transforms/TransformOsgiEntityAnnotated.java new file mode 100644 index 0000000000..b13b455b84 --- /dev/null +++ b/core/src/test/dependencies/osgi/entities/src/main/java/brooklyn/osgi/tests/transforms/TransformOsgiEntityAnnotated.java @@ -0,0 +1,27 @@ +/* + * 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 brooklyn.osgi.tests.transforms; + +import brooklyn.entity.basic.AbstractEntity; +import brooklyn.entity.rebind.transformer.TransformedBy; + +@TransformedBy(TransformOsgiEntityAnnotationTransformer.class) +public class TransformOsgiEntityAnnotated extends AbstractEntity { + +} diff --git a/core/src/test/dependencies/osgi/entities/src/main/java/brooklyn/osgi/tests/transforms/TransformOsgiEntityAnnotationTransformer.java b/core/src/test/dependencies/osgi/entities/src/main/java/brooklyn/osgi/tests/transforms/TransformOsgiEntityAnnotationTransformer.java new file mode 100644 index 0000000000..09ee0d3dac --- /dev/null +++ b/core/src/test/dependencies/osgi/entities/src/main/java/brooklyn/osgi/tests/transforms/TransformOsgiEntityAnnotationTransformer.java @@ -0,0 +1,30 @@ +/* + * 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 brooklyn.osgi.tests.transforms; + +import brooklyn.entity.rebind.transformer.RawDataTransformer; + +public class TransformOsgiEntityAnnotationTransformer implements RawDataTransformer { + + @Override + public String transform(String input) { + return TransformOsgiEntityAnnotationTransformer.class.getName(); + } + +} diff --git a/core/src/test/dependencies/osgi/entities/src/main/java/brooklyn/osgi/tests/transforms/TransformOsgiEntityNamed.java b/core/src/test/dependencies/osgi/entities/src/main/java/brooklyn/osgi/tests/transforms/TransformOsgiEntityNamed.java new file mode 100644 index 0000000000..01ec82a90d --- /dev/null +++ b/core/src/test/dependencies/osgi/entities/src/main/java/brooklyn/osgi/tests/transforms/TransformOsgiEntityNamed.java @@ -0,0 +1,25 @@ +/* + * 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 brooklyn.osgi.tests.transforms; + +import brooklyn.entity.basic.AbstractEntity; + +public class TransformOsgiEntityNamed extends AbstractEntity { + +} diff --git a/core/src/test/dependencies/osgi/entities/src/main/java/brooklyn/osgi/tests/transforms/TransformOsgiEntityNamedTransformer.java b/core/src/test/dependencies/osgi/entities/src/main/java/brooklyn/osgi/tests/transforms/TransformOsgiEntityNamedTransformer.java new file mode 100644 index 0000000000..287c56e5e9 --- /dev/null +++ b/core/src/test/dependencies/osgi/entities/src/main/java/brooklyn/osgi/tests/transforms/TransformOsgiEntityNamedTransformer.java @@ -0,0 +1,30 @@ +/* + * 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 brooklyn.osgi.tests.transforms; + +import brooklyn.entity.rebind.transformer.RawDataTransformer; + +public class TransformOsgiEntityNamedTransformer implements RawDataTransformer { + + @Override + public String transform(String input) { + return TransformOsgiEntityNamedTransformer.class.getName(); + } + +} diff --git a/core/src/test/dependencies/osgi/entities/src/main/resources/META-INF/services/brooklyn.entity.rebind.transformer.RawDataTransformer b/core/src/test/dependencies/osgi/entities/src/main/resources/META-INF/services/brooklyn.entity.rebind.transformer.RawDataTransformer new file mode 100644 index 0000000000..fcd86abfb6 --- /dev/null +++ b/core/src/test/dependencies/osgi/entities/src/main/resources/META-INF/services/brooklyn.entity.rebind.transformer.RawDataTransformer @@ -0,0 +1,19 @@ +# +# 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. +# +brooklyn.osgi.tests.TestGlobalOsgiTransformer diff --git a/core/src/test/dependencies/osgi/more-entities-v1/src/main/java/brooklyn/osgi/tests/more/TransformEntity.java b/core/src/test/dependencies/osgi/more-entities-v1/src/main/java/brooklyn/osgi/tests/more/TransformEntity.java new file mode 100644 index 0000000000..61ea5204d1 --- /dev/null +++ b/core/src/test/dependencies/osgi/more-entities-v1/src/main/java/brooklyn/osgi/tests/more/TransformEntity.java @@ -0,0 +1,32 @@ +/* + * 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 brooklyn.osgi.tests.more; + +import java.util.concurrent.Callable; + +import brooklyn.entity.Entity; +import brooklyn.event.AttributeSensor; +import brooklyn.event.basic.Sensors; + +import com.google.common.reflect.TypeToken; + +public interface TransformEntity extends Entity { + @SuppressWarnings("serial") + public static final AttributeSensor> GENERATOR = Sensors.newSensor(new TypeToken>() {}, "identity", "identity"); +} diff --git a/core/src/test/dependencies/osgi/more-entities-v1/src/main/java/brooklyn/osgi/tests/more/TransformEntityImpl.java b/core/src/test/dependencies/osgi/more-entities-v1/src/main/java/brooklyn/osgi/tests/more/TransformEntityImpl.java new file mode 100644 index 0000000000..611ad21d5b --- /dev/null +++ b/core/src/test/dependencies/osgi/more-entities-v1/src/main/java/brooklyn/osgi/tests/more/TransformEntityImpl.java @@ -0,0 +1,47 @@ +/* + * 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 brooklyn.osgi.tests.more; + +import java.util.concurrent.Callable; + +import brooklyn.entity.basic.AbstractEntity; + +public class TransformEntityImpl extends AbstractEntity implements TransformEntity { + + public static class MemoryGenerator implements Callable { + Object value; + + public MemoryGenerator(Object value) { + this.value = value; + } + + @Override + public Object call() throws Exception { + return value; + } + + } + + @Override + public void init() { + super.init(); + setAttribute(GENERATOR, new MemoryGenerator(Math.PI)); + } + +} diff --git a/core/src/test/dependencies/osgi/more-entities-v2/src/main/java/brooklyn/osgi/tests/more/TransformEntity.java b/core/src/test/dependencies/osgi/more-entities-v2/src/main/java/brooklyn/osgi/tests/more/TransformEntity.java new file mode 100644 index 0000000000..61ea5204d1 --- /dev/null +++ b/core/src/test/dependencies/osgi/more-entities-v2/src/main/java/brooklyn/osgi/tests/more/TransformEntity.java @@ -0,0 +1,32 @@ +/* + * 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 brooklyn.osgi.tests.more; + +import java.util.concurrent.Callable; + +import brooklyn.entity.Entity; +import brooklyn.event.AttributeSensor; +import brooklyn.event.basic.Sensors; + +import com.google.common.reflect.TypeToken; + +public interface TransformEntity extends Entity { + @SuppressWarnings("serial") + public static final AttributeSensor> GENERATOR = Sensors.newSensor(new TypeToken>() {}, "identity", "identity"); +} diff --git a/core/src/test/dependencies/osgi/more-entities-v2/src/main/java/brooklyn/osgi/tests/more/TransformEntityImpl.java b/core/src/test/dependencies/osgi/more-entities-v2/src/main/java/brooklyn/osgi/tests/more/TransformEntityImpl.java new file mode 100644 index 0000000000..912605998e --- /dev/null +++ b/core/src/test/dependencies/osgi/more-entities-v2/src/main/java/brooklyn/osgi/tests/more/TransformEntityImpl.java @@ -0,0 +1,45 @@ +/* + * 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 brooklyn.osgi.tests.more; + +import java.util.concurrent.Callable; + +import brooklyn.entity.basic.AbstractEntity; +import brooklyn.entity.rebind.transformer.TransformedBy; +import brooklyn.osgi.tests.more.transforms.TransformEntityTransformer; + +@TransformedBy(TransformEntityTransformer.class) +public class TransformEntityImpl extends AbstractEntity implements TransformEntity { + + public static class StaticGenerator implements Callable { + + @Override + public Object call() throws Exception { + return System.currentTimeMillis(); + } + + } + + @Override + public void init() { + super.init(); + setAttribute(GENERATOR, new StaticGenerator()); + } + +} diff --git a/core/src/test/dependencies/osgi/more-entities-v2/src/main/java/brooklyn/osgi/tests/more/transforms/TransformEntityTransformer.java b/core/src/test/dependencies/osgi/more-entities-v2/src/main/java/brooklyn/osgi/tests/more/transforms/TransformEntityTransformer.java new file mode 100644 index 0000000000..96a0e7337f --- /dev/null +++ b/core/src/test/dependencies/osgi/more-entities-v2/src/main/java/brooklyn/osgi/tests/more/transforms/TransformEntityTransformer.java @@ -0,0 +1,30 @@ +/* + * 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 brooklyn.osgi.tests.more.transforms; + +import brooklyn.entity.rebind.transformer.RawDataTransformer; + +public class TransformEntityTransformer implements RawDataTransformer { + + @Override + public String transform(String input) { + return null; + } + +} diff --git a/core/src/test/java/brooklyn/entity/rebind/ActivePartialRebindTest.java b/core/src/test/java/brooklyn/entity/rebind/ActivePartialRebindTest.java index afeca2be22..64314b9dfe 100644 --- a/core/src/test/java/brooklyn/entity/rebind/ActivePartialRebindTest.java +++ b/core/src/test/java/brooklyn/entity/rebind/ActivePartialRebindTest.java @@ -36,11 +36,6 @@ public class ActivePartialRebindTest extends RebindTestFixtureWithApp { private static final Logger log = LoggerFactory.getLogger(ActivePartialRebindTest.class); - protected void doPartialRebindOfIds(String ...objectsToRebindIds) { - RebindManagerImpl rm = (RebindManagerImpl) origManagementContext.getRebindManager(); - rm.rebindPartialActive(null, objectsToRebindIds); - } - @Test public void testRebindChildSimple() throws Exception { TestEntity c1 = origApp.addChild(EntitySpec.create(TestEntity.class)); diff --git a/core/src/test/java/brooklyn/entity/rebind/RebindEntityTest.java b/core/src/test/java/brooklyn/entity/rebind/RebindEntityTest.java index 9b1e05d0c9..bc08009090 100644 --- a/core/src/test/java/brooklyn/entity/rebind/RebindEntityTest.java +++ b/core/src/test/java/brooklyn/entity/rebind/RebindEntityTest.java @@ -204,7 +204,7 @@ public void testRestoresEntityLocationAndCleansUp() throws Exception { RebindTestUtils.waitForPersisted(origManagementContext); BrooklynMementoManifest mf = loadMementoManifest(); - Assert.assertTrue(mf.getLocationIdToType().isEmpty(), "Expected no locations; had "+mf.getLocationIdToType()); + Assert.assertTrue(mf.getLocationIdToManifest().isEmpty(), "Expected no locations; had "+mf.getLocationIdToManifest()); } @Test diff --git a/core/src/test/java/brooklyn/entity/rebind/RebindLocalhostLocationTest.java b/core/src/test/java/brooklyn/entity/rebind/RebindLocalhostLocationTest.java index 00e88d71fe..aafa54990e 100644 --- a/core/src/test/java/brooklyn/entity/rebind/RebindLocalhostLocationTest.java +++ b/core/src/test/java/brooklyn/entity/rebind/RebindLocalhostLocationTest.java @@ -99,7 +99,7 @@ public void testMachineCleansUp() throws Exception { RebindTestUtils.waitForPersisted(origManagementContext); BrooklynMementoManifest mf = loadMementoManifest(); - Assert.assertTrue(mf.getLocationIdToType().isEmpty(), "Expected no locations; had "+mf.getLocationIdToType()); + Assert.assertTrue(mf.getLocationIdToManifest().isEmpty(), "Expected no locations; had "+mf.getLocationIdToManifest()); } } diff --git a/core/src/test/java/brooklyn/entity/rebind/RebindPolicyTest.java b/core/src/test/java/brooklyn/entity/rebind/RebindPolicyTest.java index 1f073ed140..d90ed0857c 100644 --- a/core/src/test/java/brooklyn/entity/rebind/RebindPolicyTest.java +++ b/core/src/test/java/brooklyn/entity/rebind/RebindPolicyTest.java @@ -142,9 +142,9 @@ public void testExpungesOnEntityUnmanaged() throws Exception { BrooklynMementoManifest manifest = loadMementoManifest(); assertFalse(manifest.getEntityIdToManifest().containsKey(entity.getId())); - assertFalse(manifest.getPolicyIdToType().containsKey(policy.getId())); - assertFalse(manifest.getEnricherIdToType().containsKey(enricher.getId())); - assertFalse(manifest.getLocationIdToType().containsKey(loc.getId())); + assertFalse(manifest.getPolicyIdToManifest().containsKey(policy.getId())); + assertFalse(manifest.getEnricherIdToManifest().containsKey(enricher.getId())); + assertFalse(manifest.getLocationIdToManifest().containsKey(loc.getId())); } @Test @@ -160,8 +160,8 @@ public void testExpungesOnPolicyRemoved() throws Exception { RebindTestUtils.waitForPersisted(origApp); BrooklynMementoManifest manifest = loadMementoManifest(); - assertFalse(manifest.getPolicyIdToType().containsKey(policy.getId())); - assertFalse(manifest.getEnricherIdToType().containsKey(enricher.getId())); + assertFalse(manifest.getPolicyIdToManifest().containsKey(policy.getId())); + assertFalse(manifest.getEnricherIdToManifest().containsKey(enricher.getId())); } @Test diff --git a/core/src/test/java/brooklyn/entity/rebind/RebindTestFixture.java b/core/src/test/java/brooklyn/entity/rebind/RebindTestFixture.java index c307aa409e..8fe2f829bf 100644 --- a/core/src/test/java/brooklyn/entity/rebind/RebindTestFixture.java +++ b/core/src/test/java/brooklyn/entity/rebind/RebindTestFixture.java @@ -322,4 +322,10 @@ protected void assertCatalogDoesNotContain(BrooklynCatalog catalog, String symbo CatalogItem found = catalog.getCatalogItem(symbolicName, version); assertNull(found); } + + protected void doPartialRebindOfIds(String ...objectsToRebindIds) { + RebindManagerImpl rm = (RebindManagerImpl) origManagementContext.getRebindManager(); + rm.rebindPartialActive(null, objectsToRebindIds); + } + } diff --git a/core/src/test/java/brooklyn/entity/rebind/transformer/CompoundTransformerLoaderTest.java b/core/src/test/java/brooklyn/entity/rebind/transformer/CompoundTransformerLoaderTest.java index b23f1bd176..a12c9362df 100644 --- a/core/src/test/java/brooklyn/entity/rebind/transformer/CompoundTransformerLoaderTest.java +++ b/core/src/test/java/brooklyn/entity/rebind/transformer/CompoundTransformerLoaderTest.java @@ -70,7 +70,7 @@ public void testLoadsTransformerFromYaml() throws Exception { public static class MyRawDataTransformer implements RawDataTransformer { @Override - public String transform(String input) throws Exception { + public String transform(String input) { return input; // no-op } } diff --git a/core/src/test/java/brooklyn/entity/rebind/transformer/EntityTransformerTest.java b/core/src/test/java/brooklyn/entity/rebind/transformer/EntityTransformerTest.java new file mode 100644 index 0000000000..2f380e8185 --- /dev/null +++ b/core/src/test/java/brooklyn/entity/rebind/transformer/EntityTransformerTest.java @@ -0,0 +1,111 @@ +/* + * 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 brooklyn.entity.rebind.transformer; + +import static org.testng.Assert.assertEquals; + +import java.util.concurrent.Callable; + +import org.testng.annotations.Test; + +import brooklyn.entity.Entity; +import brooklyn.entity.basic.AbstractEntity; +import brooklyn.entity.proxying.EntitySpec; +import brooklyn.entity.proxying.ImplementedBy; +import brooklyn.entity.rebind.RebindTestFixtureWithApp; +import brooklyn.event.AttributeSensor; +import brooklyn.event.basic.Sensors; + +import com.google.common.base.Predicates; +import com.google.common.collect.Iterables; +import com.google.common.reflect.TypeToken; + +public class EntityTransformerTest extends RebindTestFixtureWithApp { + @Test + public void testRebindTransformer() throws Exception { + Entity oldE = origApp.createAndManageChild(EntitySpec.create(TransformEntity.class)); + assertEquals(oldE.getAttribute(TransformEntity.GENERATOR).call(), Math.PI); + + //global transformer loading is not test-friendly + // 1. GlobalTestTransformer will rename the entity being used, simulating library upgrade (can't use catalog items here) + // 2. TransformEntityTransformer will try to upgrade the entity on the fly + newApp = rebind(); + Entity newE = Iterables.find(newApp.getChildren(), Predicates.instanceOf(TransformEntity.class)); + assertEquals(newE.getAttribute(TransformEntity.GENERATOR).call(), "static"); + } + + @Test + public void testPartialRebindTransformer() throws Exception { + Entity entity = origApp.createAndManageChild(EntitySpec.create(TransformEntity.class)); + assertEquals(entity.getAttribute(TransformEntity.GENERATOR).call(), Math.PI); + + doPartialRebindOfIds(entity.getId()); + assertEquals(entity.getAttribute(TransformEntity.GENERATOR).call(), "static"); + } + + @ImplementedBy(TransformEntityImplV1.class) + public interface TransformEntity extends Entity { + @SuppressWarnings("serial") + public static final AttributeSensor> GENERATOR = Sensors.newSensor(new TypeToken>() {}, "identity", "identity"); + } + + public static class TransformEntityImplV1 extends AbstractEntity implements TransformEntity { + + public static class MemoryGenerator implements Callable { + Object value; + + public MemoryGenerator(Object value) { + this.value = value; + } + + @Override + public Object call() throws Exception { + return value; + } + + } + + @Override + public void init() { + super.init(); + setAttribute(GENERATOR, new MemoryGenerator(Math.PI)); + } + + } + + @TransformedBy(TransformEntityTransformer.class) + public static class TransformEntityImplV2 extends AbstractEntity implements TransformEntity { + + public static class StaticGenerator implements Callable { + + @Override + public Object call() throws Exception { + return "static"; + } + + } + + @Override + public void init() { + super.init(); + setAttribute(GENERATOR, new StaticGenerator()); + } + + } +} diff --git a/core/src/test/java/brooklyn/entity/rebind/transformer/GlobalTestTransformer.java b/core/src/test/java/brooklyn/entity/rebind/transformer/GlobalTestTransformer.java new file mode 100644 index 0000000000..9f8c17c64f --- /dev/null +++ b/core/src/test/java/brooklyn/entity/rebind/transformer/GlobalTestTransformer.java @@ -0,0 +1,34 @@ +/* + * 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 brooklyn.entity.rebind.transformer; + +import brooklyn.entity.rebind.transformer.RawDataTransformer; + +public class GlobalTestTransformer implements RawDataTransformer { + + @Override + public String transform(String input) { + if ("test".equals(input)) { + return GlobalTestTransformer.class.getSimpleName(); + } else { + return input.replace("TransformEntityImplV1", "TransformEntityImplV2"); + } + } + +} diff --git a/core/src/test/java/brooklyn/entity/rebind/transformer/TransformEntityAnnotated.java b/core/src/test/java/brooklyn/entity/rebind/transformer/TransformEntityAnnotated.java new file mode 100644 index 0000000000..cea7b3c2e2 --- /dev/null +++ b/core/src/test/java/brooklyn/entity/rebind/transformer/TransformEntityAnnotated.java @@ -0,0 +1,27 @@ +/* + * 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 brooklyn.entity.rebind.transformer; + +import brooklyn.entity.basic.AbstractEntity; +import brooklyn.entity.rebind.transformer.TransformedBy; + +@TransformedBy(TransformEntityAnnotationTransformer.class) +public class TransformEntityAnnotated extends AbstractEntity { + +} diff --git a/core/src/test/java/brooklyn/entity/rebind/transformer/TransformEntityAnnotationTransformer.java b/core/src/test/java/brooklyn/entity/rebind/transformer/TransformEntityAnnotationTransformer.java new file mode 100644 index 0000000000..3f0a0a40b8 --- /dev/null +++ b/core/src/test/java/brooklyn/entity/rebind/transformer/TransformEntityAnnotationTransformer.java @@ -0,0 +1,30 @@ +/* + * 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 brooklyn.entity.rebind.transformer; + +import brooklyn.entity.rebind.transformer.RawDataTransformer; + +public class TransformEntityAnnotationTransformer implements RawDataTransformer { + + @Override + public String transform(String input) { + return TransformEntityAnnotationTransformer.class.getName(); + } + +} diff --git a/core/src/test/java/brooklyn/entity/rebind/transformer/TransformEntityNamed.java b/core/src/test/java/brooklyn/entity/rebind/transformer/TransformEntityNamed.java new file mode 100644 index 0000000000..4f726316fa --- /dev/null +++ b/core/src/test/java/brooklyn/entity/rebind/transformer/TransformEntityNamed.java @@ -0,0 +1,25 @@ +/* + * 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 brooklyn.entity.rebind.transformer; + +import brooklyn.entity.basic.AbstractEntity; + +public class TransformEntityNamed extends AbstractEntity { + +} diff --git a/core/src/test/java/brooklyn/entity/rebind/transformer/TransformEntityNamedTransformer.java b/core/src/test/java/brooklyn/entity/rebind/transformer/TransformEntityNamedTransformer.java new file mode 100644 index 0000000000..e70d0cdd9f --- /dev/null +++ b/core/src/test/java/brooklyn/entity/rebind/transformer/TransformEntityNamedTransformer.java @@ -0,0 +1,30 @@ +/* + * 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 brooklyn.entity.rebind.transformer; + +import brooklyn.entity.rebind.transformer.RawDataTransformer; + +public class TransformEntityNamedTransformer implements RawDataTransformer { + + @Override + public String transform(String input) { + return TransformEntityNamedTransformer.class.getName(); + } + +} diff --git a/core/src/test/java/brooklyn/entity/rebind/transformer/TransformEntityTransformer.java b/core/src/test/java/brooklyn/entity/rebind/transformer/TransformEntityTransformer.java new file mode 100644 index 0000000000..68709e1fe7 --- /dev/null +++ b/core/src/test/java/brooklyn/entity/rebind/transformer/TransformEntityTransformer.java @@ -0,0 +1,28 @@ +/* + * 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 brooklyn.entity.rebind.transformer; + +public class TransformEntityTransformer implements RawDataTransformer { + + @Override + public String transform(String input) { + return input.replace("MemoryGenerator", "StaticGenerator").replace("3.141592653589793", ""); + } + +} diff --git a/core/src/test/java/brooklyn/entity/rebind/transformer/TransformerLoaderTest.java b/core/src/test/java/brooklyn/entity/rebind/transformer/TransformerLoaderTest.java new file mode 100644 index 0000000000..b93371b677 --- /dev/null +++ b/core/src/test/java/brooklyn/entity/rebind/transformer/TransformerLoaderTest.java @@ -0,0 +1,120 @@ +/* + * 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 brooklyn.entity.rebind.transformer; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import org.osgi.framework.BundleException; +import org.osgi.framework.launch.Framework; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import brooklyn.catalog.internal.CatalogBundleDto; +import brooklyn.catalog.internal.CatalogEntityItemDto; +import brooklyn.catalog.internal.CatalogItemBuilder; +import brooklyn.catalog.internal.CatalogUtils; +import brooklyn.entity.basic.Entities; +import brooklyn.entity.rebind.TransformerLoader; +import brooklyn.entity.rebind.dto.MementoManifestImpl; +import brooklyn.entity.rebind.transformer.RawDataTransformer; +import brooklyn.management.internal.LocalManagementContext; +import brooklyn.management.osgi.OsgiStandaloneTest; +import brooklyn.management.osgi.OsgiTestResources; +import brooklyn.mementos.BrooklynMementoManifest.MementoManifest; +import brooklyn.test.TestResourceUnavailableException; +import brooklyn.test.entity.LocalManagementContextForTests; +import brooklyn.util.osgi.Osgis; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; + +public class TransformerLoaderTest { + private LocalManagementContext mgmt; + + @BeforeMethod(alwaysRun=true) + private void setUp() throws BundleException { + TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_PATH); + + mgmt = LocalManagementContextForTests.builder(true).disableOsgi(false).build(); + Framework framework = mgmt.getOsgiManager().get().getFramework(); + Osgis.install(framework, OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_PATH); + } + + @AfterMethod(alwaysRun=true) + private void tearDown() { + Entities.destroyAll(mgmt); + } + + @Test + public void testLoadsGlobalTransformers() throws Exception { + Collection transformers = new TransformerLoader(mgmt).findGlobalTransformers(); + assertEquals(transformers.size(), 2, "One transformer in core, one in osgi bundle"); + Set transformerNames = new HashSet(); + for (RawDataTransformer t : transformers) { + transformerNames.add(t.getClass().getSimpleName()); + assertEquals(t.transform("test"), t.getClass().getSimpleName()); + } + + assertTrue(transformerNames.contains("GlobalTestTransformer"), "Missing TestGlobalTransformer"); + assertTrue(transformerNames.contains("TestGlobalOsgiTransformer"), "Missing TestGlobalOsgiTransformer"); + } + + @DataProvider(name="transformers") + public Object[][] trasnfromers() { + return new Object[][] { + {TransformEntityAnnotated.class.getName(), + TransformEntityAnnotationTransformer.class.getName(), + null}, + {TransformEntityNamed.class.getName(), + TransformEntityNamedTransformer.class.getName(), + null}, + {"brooklyn.osgi.tests.transforms.TransformOsgiEntityAnnotated", + "brooklyn.osgi.tests.transforms.TransformOsgiEntityAnnotationTransformer", + OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_PATH}, + {"brooklyn.osgi.tests.transforms.TransformOsgiEntityNamed", + "brooklyn.osgi.tests.transforms.TransformOsgiEntityNamedTransformer", + OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_PATH} + }; + } + + @Test(dataProvider="transformers") + public void testLoadsBlueprintTransformers(String entityType, String transformerType, String jarPath) throws Exception { + String catalogItemId = null; + if (jarPath != null) { + TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), jarPath); + CatalogEntityItemDto item = CatalogItemBuilder.newEntity("test", "1.0") + .libraries(ImmutableList.of(new CatalogBundleDto(null, null, "classpath:" + jarPath))) + .build(); + mgmt.getCatalog().addItem(item); + catalogItemId = CatalogUtils.getVersionedId(item.getSymbolicName(), item.getVersion()); + } + MementoManifest manifest = new MementoManifestImpl("", entityType, null, catalogItemId); + Collection transformers = new TransformerLoader(mgmt).findBlueprintTransformers(manifest); + RawDataTransformer transformer = Iterables.getOnlyElement(transformers); + assertEquals(transformer.getClass().getName(), transformerType); + assertEquals(transformer.transform(""), transformer.getClass().getName()); + } +} diff --git a/core/src/test/resources/META-INF/services/brooklyn.entity.rebind.transformer.RawDataTransformer b/core/src/test/resources/META-INF/services/brooklyn.entity.rebind.transformer.RawDataTransformer new file mode 100644 index 0000000000..3760cbe965 --- /dev/null +++ b/core/src/test/resources/META-INF/services/brooklyn.entity.rebind.transformer.RawDataTransformer @@ -0,0 +1,19 @@ +# +# 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. +# +brooklyn.entity.rebind.transformer.GlobalTestTransformer diff --git a/core/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-entities.jar b/core/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-entities.jar index 6e2e80d5a4..1573dc0fd9 100644 Binary files a/core/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-entities.jar and b/core/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-entities.jar differ