You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by he...@apache.org on 2017/06/30 14:03:05 UTC

[17/27] brooklyn-server git commit: record underlying supplied version in VersionedName

record underlying supplied version in VersionedName

support for persistence, and test


Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/89fb1395
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/89fb1395
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/89fb1395

Branch: refs/heads/master
Commit: 89fb13955eef518f53e3c3330a20191c89a3cf2e
Parents: d8c03c8
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Thu Jun 22 13:17:32 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Thu Jun 22 14:12:02 2017 +0100

----------------------------------------------------------------------
 .../core/mgmt/rebind/MiscClassesRebindTest.java | 127 +++++++++++++++++++
 ...7-06-versionedname-entity-n7p20t5h4o.memento |  42 ++++++
 .../brooklyn/util/osgi/VersionedName.java       |  90 ++++++++++---
 3 files changed, 239 insertions(+), 20 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/89fb1395/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/MiscClassesRebindTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/MiscClassesRebindTest.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/MiscClassesRebindTest.java
new file mode 100644
index 0000000..bbc40d0
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/MiscClassesRebindTest.java
@@ -0,0 +1,127 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.core.mgmt.rebind;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.util.Date;
+import java.util.concurrent.TimeoutException;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.test.entity.TestApplication;
+import org.apache.brooklyn.test.Asserts;
+import org.apache.brooklyn.util.javalang.JavaClassNames;
+import org.apache.brooklyn.util.os.Os;
+import org.apache.brooklyn.util.osgi.VersionedName;
+import org.apache.brooklyn.util.stream.Streams;
+import org.apache.brooklyn.util.time.Time;
+import org.osgi.framework.Version;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.google.common.io.Files;
+
+/** Tests ability to rebind to previous version serialization state, for various classes; 
+ * and utils to create such state (edit the config key value then run main method). 
+ */
+public class MiscClassesRebindTest extends RebindTestFixtureWithApp {
+
+    private static final ConfigKey<Object> TEST_KEY = ConfigKeys.builder(Object.class).name("testKey").build();
+    private static final Logger log = LoggerFactory.getLogger(MiscClassesRebindTest.class);
+
+    /** Method to facilitate creation of memento files */
+    private void createMemento() throws Exception {
+        setUp();
+        origApp = super.createApp();
+        
+        // edit this, run this class's main method, then use the log output for your test case
+        origApp.config().set(TEST_KEY,  new VersionedName("foo", Version.parseVersion("1.0.0.foo")));
+
+        
+        RebindTestUtils.stopPersistence(origApp);
+        String fn = mementoDir + File.separator + "entities" + File.separator + origApp.getApplicationId();
+        log.info("Persisted to "+fn);
+        String yyyyMM = Time.makeDateString(new Date(), "yyyy-MM");
+        log.info("Set up your tests by copying from the persistence dir "+mementoDir+"\n\n"+
+            "cp "+fn+" "+
+            "src/test/resources/"+getClass().getPackage().getName().replaceAll("\\.", "/")+"/"+
+            JavaClassNames.cleanSimpleClassName(this)+"-"+yyyyMM+"-entity-"+origApp.getApplicationId()+".memento\n");
+        String content = Streams.readFullyString(new FileInputStream(new File(fn)));
+        log.info("Or paste the following contents there:\n"+content);
+        log.info("Then add the apache comment header there, and write your test doing  loadEntityMemento(\""+yyyyMM+"\", \""+origApp.getApplicationId()+"\")");
+    }
+    
+    public static void main(String[] args) throws Exception {
+        new MiscClassesRebindTest().createMemento();
+        // halt to keep memento dir
+        Runtime.getRuntime().halt(0);
+    }
+    
+    
+    public TestApplication createApp() { /* no-op here for most tests */ return null; }
+    
+    protected Entity loadEntityMemento(String label, String entityId) throws Exception {
+        String mementoResourceName = JavaClassNames.cleanSimpleClassName(this) + "-" + label + "-entity-" + entityId+".memento";
+        String memento = Streams.readFullyString(getClass().getResourceAsStream(mementoResourceName));
+        
+        File persistedEntityFile = new File(mementoDir, Os.mergePaths("entities", entityId));
+        Files.write(memento.getBytes(), persistedEntityFile);
+        
+        return newApp = rebind();
+    }
+
+    protected String getEntityMementoContent() throws InterruptedException, TimeoutException, FileNotFoundException {
+        RebindTestUtils.stopPersistence(newApp);
+        String fn = mementoDir + File.separator + "entities" + File.separator + newApp.getApplicationId();
+        return Streams.readFullyString(new FileInputStream(new File(fn)));
+    }
+
+    @SuppressWarnings("unchecked")
+    protected <T> T getTestKeyFromEntityMemento(String label, String entityId, Class<T> type) throws Exception {
+        Entity e = loadEntityMemento(label, entityId);
+        return (T) e.getConfig(TEST_KEY);
+    }
+
+    
+    @Test
+    public void testVersionedName() throws Exception {
+        VersionedName vn = getTestKeyFromEntityMemento("2017-06-versionedname", "n7p20t5h4o", VersionedName.class);
+        Assert.assertEquals(vn, new VersionedName("foo", "1.0.0-foo"));
+        Assert.assertNotEquals(vn, new VersionedName("foo", "1.0.0.foo"));
+        Assert.assertTrue(vn.equalsOsgi(new VersionedName("foo", Version.parseVersion("1.0.0.foo"))));
+        
+        String newEntityContent = getEntityMementoContent();
+        // log.info("New VN persistence is\n"+newEntityContent);
+        Asserts.assertStringContains(newEntityContent, "1.0.0-foo");
+        // phrases from original persisted state are changed
+        Asserts.assertStringDoesNotContain(newEntityContent, "<symbolicName>foo");
+        Asserts.assertStringDoesNotContain(newEntityContent, "<version>1.0.0");
+        Asserts.assertStringDoesNotContain(newEntityContent, "1.0.0.foo");
+        // they should now be this
+        Asserts.assertStringContains(newEntityContent, "<name>foo");
+        Asserts.assertStringContains(newEntityContent, "<v>1.0.0-foo");
+    }
+
+}
+

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/89fb1395/core/src/test/resources/org/apache/brooklyn/core/mgmt/rebind/MiscClassesRebindTest-2017-06-versionedname-entity-n7p20t5h4o.memento
----------------------------------------------------------------------
diff --git a/core/src/test/resources/org/apache/brooklyn/core/mgmt/rebind/MiscClassesRebindTest-2017-06-versionedname-entity-n7p20t5h4o.memento b/core/src/test/resources/org/apache/brooklyn/core/mgmt/rebind/MiscClassesRebindTest-2017-06-versionedname-entity-n7p20t5h4o.memento
new file mode 100644
index 0000000..0b98cbd
--- /dev/null
+++ b/core/src/test/resources/org/apache/brooklyn/core/mgmt/rebind/MiscClassesRebindTest-2017-06-versionedname-entity-n7p20t5h4o.memento
@@ -0,0 +1,42 @@
+<!--
+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.
+-->
+
+<entity>
+  <brooklynVersion>0.12.0-SNAPSHOT</brooklynVersion>
+  <type>org.apache.brooklyn.core.test.entity.TestApplicationNoEnrichersImpl</type>
+  <id>n7p20t5h4o</id>
+  <displayName>TestApplicationNoEnrichersImpl:n7p2</displayName>
+  <config>
+    <testKey>
+      <org.apache.brooklyn.util.osgi.VersionedName>
+        <symbolicName>foo</symbolicName>
+        <version>
+          <major>1</major>
+          <minor>0</minor>
+          <micro>0</micro>
+          <qualifier>foo</qualifier>
+        </version>
+      </org.apache.brooklyn.util.osgi.VersionedName>
+    </testKey>
+  </config>
+  <attributes>
+    <entity.id>n7p20t5h4o</entity.id>
+    <application.id>n7p20t5h4o</application.id>
+  </attributes>
+</entity>

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/89fb1395/utils/common/src/main/java/org/apache/brooklyn/util/osgi/VersionedName.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/osgi/VersionedName.java b/utils/common/src/main/java/org/apache/brooklyn/util/osgi/VersionedName.java
index 5807904..e466d82 100644
--- a/utils/common/src/main/java/org/apache/brooklyn/util/osgi/VersionedName.java
+++ b/utils/common/src/main/java/org/apache/brooklyn/util/osgi/VersionedName.java
@@ -19,52 +19,93 @@ import static com.google.common.base.Preconditions.checkNotNull;
 
 import javax.annotation.Nullable;
 
-import com.google.common.base.Objects;
-import org.apache.brooklyn.util.text.Strings;
+import org.apache.brooklyn.util.text.BrooklynVersionSyntax;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.Version;
 
-/**
- * Versioned name of an OSGi bundle.
- * @author Ciprian Ciubotariu <ch...@gmx.net>
- */
+import com.google.common.base.Objects;
+
+/** Records a name (string) and version (string),
+ * with conveniences for pretty-printing and converting to OSGi format. */
 public class VersionedName {
-    private final String symbolicName;
-    private final Version version;
+    private final String name;
+    private final String v;
+    
+    @Deprecated // since 0.12.0 - remove along with version and readResolve in 0.13.0
+    private final String symbolicName = null;
+    @Deprecated // since 0.12.0
+    private final Version version = null;
+    
 
+    private Object readResolve() {
+        if (symbolicName!=null || version!=null) {
+            // remove legacy fields, and convert to brooklyn recommended version in the process
+            // (might be slightly weird if bundles are persisted, but code will forgive that,
+            // and if types were persisted this will do the right thing)
+            return new VersionedName(symbolicName, BrooklynVersionSyntax.toGoodBrooklynVersion( version.toString() ));
+        }
+        return this;
+    }
+    
     public VersionedName(Bundle b) {
-        this(b.getSymbolicName(), b.getVersion());
+        this(b.getSymbolicName(), b.getVersion().toString());
     }
 
-    public VersionedName(String symbolicName, @Nullable Version version) {
-        this.symbolicName = checkNotNull(symbolicName, "symbolicName");
-        this.version = version;
+    public VersionedName(String name, String v) {
+        this.name = checkNotNull(name, "name");
+        this.v = v;
+    }
+    public VersionedName(String name, @Nullable Version v) {
+        this.name = checkNotNull(name, "name").toString();
+        this.v = v==null ? null : v.toString();
     }
 
+    
     @Override
     public String toString() {
-        return symbolicName + ":" + Strings.toString(version);
+        return name + ":" + v;
+    }
+    
+    public String toOsgiString() {
+        return name + ":" + getOsgiVersion();
     }
 
     public boolean equals(String sn, String v) {
-        return symbolicName.equals(sn) && (version == null && v == null || version != null && version.toString().equals(v));
+        return name.equals(sn) && Objects.equal(this.v, v);
+        // could also consider equal if the osgi mapping is equal (but for now we don't; if caller wants that, they should create Version)
+        // || (v!=null && Version.parseVersion(BrooklynVersionSyntax.toValidOsgiVersion(v)).equals(getOsgiVersion())));
     }
 
     public boolean equals(String sn, Version v) {
-        return symbolicName.equals(sn) && (version == null && v == null || version != null && version.equals(v));
+        return name.equals(sn) && Objects.equal(getOsgiVersion(), v);
     }
 
     public String getSymbolicName() {
-        return symbolicName;
+        return name;
     }
 
+    private transient Version cachedOsgiVersion;
+    @Nullable
+    public Version getOsgiVersion() {
+        if (cachedOsgiVersion==null && v!=null) {
+            cachedOsgiVersion = v==null ? null : Version.parseVersion(BrooklynVersionSyntax.toValidOsgiVersion(v));
+        }
+        return cachedOsgiVersion;
+    }
+
+    @Nullable
+    public String getVersionString() {
+        return v;
+    }
+    
+    @Deprecated /** @deprecated since 0.12.0 use {@link #getVersionString()} or {@link #getOsgiVersion()} */
     public Version getVersion() {
-        return version;
+        return getOsgiVersion();
     }
 
     @Override
     public int hashCode() {
-        return Objects.hashCode(symbolicName, version);
+        return Objects.hashCode(name, v);
     }
 
     @Override
@@ -73,14 +114,23 @@ public class VersionedName {
             return false;
         }
         VersionedName o = (VersionedName) other;
-        return Objects.equal(symbolicName, o.symbolicName) && Objects.equal(version, o.version);
+        return Objects.equal(name, o.name) && Objects.equal(v, o.v);
+    }
+    
+    /** As {@link #equals(Object)} but accepting the argument as equal if versions are identical when injected to OSGi-valid versions */
+    public boolean equalsOsgi(Object other) {
+        if (!(other instanceof VersionedName)) {
+            return false;
+        }
+        VersionedName o = (VersionedName) other;
+        return Objects.equal(name, o.name) && Objects.equal(getOsgiVersion(), o.getOsgiVersion());        
     }
 
     public static VersionedName fromString(String nameOptionalColonVersion) {
         if (nameOptionalColonVersion==null) return null;
         int colon = nameOptionalColonVersion.indexOf(':');
         if (colon<0) throw new IllegalArgumentException("Versioned name '"+nameOptionalColonVersion+"' must be of form 'name:version'");
-        return new VersionedName(nameOptionalColonVersion.substring(0, colon), Version.parseVersion(nameOptionalColonVersion.substring(colon+1)));
+        return new VersionedName(nameOptionalColonVersion.substring(0, colon), nameOptionalColonVersion.substring(colon+1));
     }
 
 }