Author: jboynes
Date: Mon Feb 21 13:19:07 2005
New Revision: 154723
URL: http://svn.apache.org/viewcvs?view=rev&rev=154723
Log:
initial impl of GBeanName
Added:
geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/GBeanName.java
geronimo/trunk/modules/kernel/src/test/org/apache/geronimo/gbean/GBeanNameTest.java
Added:
geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/GBeanName.java
URL:
http://svn.apache.org/viewcvs/geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/GBeanName.java?view=auto&rev=154723
==============================================================================
---
geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/GBeanName.java
(added)
+++
geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/GBeanName.java
Mon Feb 21 13:19:07 2005
@@ -0,0 +1,184 @@
+/**
+ *
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * Licensed 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.geronimo.gbean;
+
+import java.io.Serializable;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+
+
+/**
+ * Class that represents the name for a GBean.
+ * A name is comprised of a domain combined with one or more properties.
+ * The domain is a fixed base name, properties qualify that as necessary.
+ * Two names are equal if they have the same name and the same properties.
+ * The String representation of a name can be written as
domain:key1=value1,key2=value2,...
+ * Values are case sensitive, spaces are significant and there is no escaping
mechanism;
+ * this is intended to be fast rather than allow lax syntax.
+ *
+ * @version $Rev$ $Date$
+ */
+public final class GBeanName implements Serializable {
+ private static final long serialVersionUID = 8571821054715922993L;
+
+ /**
+ * Original name preserved; used for toString and Serialized form
+ */
+ private final String name;
+ private final transient String domain;
+ private final transient Properties props;
+ private final transient int hashCode;
+
+ /**
+ * Construct a GBeanName by combining a domain with explicit properties.
+ * The string representation of this name is generated by combining the
properties in sorted order.
+ *
+ * @param domain the domain
+ * @param props the properties used to qualify this name
+ */
+ public GBeanName(String domain, Properties props) {
+ if (domain == null) {
+ throw new IllegalArgumentException("domain is null");
+ } else if (props == null) {
+ throw new IllegalArgumentException("props is null");
+ } else if (props.isEmpty()) {
+ throw new IllegalArgumentException("props is empty");
+ }
+ this.domain = domain;
+ this.props = new Properties(props);
+ this.name = sortName(domain, props);
+ this.hashCode = domain.hashCode() + 37 * props.hashCode();
+ }
+
+ /**
+ * Construct a GBeanName by parsing a string.
+ * @param name the name to parse
+ */
+ public GBeanName(String name) {
+ int idx = name.indexOf(':');
+ if (idx == -1) {
+ throw new IllegalArgumentException("Missing ':' for domain: " +
name);
+ }
+ this.name = name;
+ this.domain = name.substring(0, idx);
+ this.props = parseName(name.substring(idx + 1));
+ this.hashCode = domain.hashCode() + 37 * props.hashCode();
+ }
+
+ private static Properties parseName(String name) {
+ if (name.endsWith(",")) {
+ throw new IllegalArgumentException("Missing last property pair");
+ }
+ Properties props = new Properties();
+ String[] pairs = name.split(",");
+ for (int i = 0; i < pairs.length; i++) {
+ String pair = pairs[i];
+ int idx = pair.indexOf('=');
+ if (idx == -1) {
+ throw new IllegalArgumentException("Invalid property pair: " +
pair);
+ }
+ String key = pair.substring(0, idx);
+ String value = pair.substring(idx + 1);
+ if (props.put(key, value) != null) {
+ throw new IllegalArgumentException("Duplicate property: " +
key);
+ }
+ }
+ return props;
+ }
+
+ private static String sortName(String domain, Map props) {
+ String[] names = (String[]) props.keySet().toArray(new
String[props.size()]);
+ Arrays.sort(names);
+ StringBuffer buf = new StringBuffer(128);
+ buf.append(domain).append(':');
+ buf.append(names[0]).append('=').append(props.get(names[0]));
+ for (int i = 1; i < names.length; i++) {
+ String name = names[i];
+ buf.append(',').append(name).append('=').append(props.get(name));
+ }
+ return buf.toString();
+ }
+
+ /**
+ * Determine if this name matches the supplied pattern.
+ * This performs a fast but simplistic pattern match which is true if:
+ * <ul>
+ * <li>The domains are equal</li>
+ * <li>If this instance has all the supplied properties with equal
values</li>
+ * <ul>
+ * A null domain and a null or empty properties object are considered
wildcards
+ * and always match; in other words GBeanName.match(null, new
Properties()) will
+ * always evaluate to true.
+ *
+ * @param domain the domain to match
+ * @param pattern the set properties to match
+ * @return true if this instance matches the pattern
+ */
+ public boolean matches(String domain, Properties pattern) {
+ if (domain != null) {
+ if (!this.domain.equals(domain)) {
+ return false;
+ }
+ }
+ if (pattern != null && !pattern.isEmpty()) {
+ for (Iterator i = pattern.entrySet().iterator(); i.hasNext();) {
+ Map.Entry entry = (Map.Entry) i.next();
+ String key = (String) entry.getKey();
+ String ourValue = (String) props.get(key);
+ if (ourValue == null || !ourValue.equals(entry.getValue())) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Test for equality.
+ * This instance will be equal if the supplied object is a GBeanName with
+ * equal domain and properties.
+ * @param obj
+ * @return
+ */
+ public boolean equals(Object obj) {
+ if (obj == this) return true;
+ if (obj instanceof GBeanName == false) return false;
+ final GBeanName other = (GBeanName) obj;
+ return this.domain.equals(other.domain) &&
this.props.equals(other.props);
+ }
+
+ public int hashCode() {
+ return hashCode;
+ }
+
+ /**
+ * Return a human readable version of this GBeanName. If the instance was
created
+ * by parsing a String, this will be the supplied value; it it was created
by
+ * supplying properties, the name will contain properties in sorted order.
+ *
+ * @return a readable name
+ */
+ public String toString() {
+ return name;
+ }
+
+ private Object readResolve() {
+ return new GBeanName(name);
+ }
+}
\ No newline at end of file
Added:
geronimo/trunk/modules/kernel/src/test/org/apache/geronimo/gbean/GBeanNameTest.java
URL:
http://svn.apache.org/viewcvs/geronimo/trunk/modules/kernel/src/test/org/apache/geronimo/gbean/GBeanNameTest.java?view=auto&rev=154723
==============================================================================
---
geronimo/trunk/modules/kernel/src/test/org/apache/geronimo/gbean/GBeanNameTest.java
(added)
+++
geronimo/trunk/modules/kernel/src/test/org/apache/geronimo/gbean/GBeanNameTest.java
Mon Feb 21 13:19:07 2005
@@ -0,0 +1,157 @@
+/**
+ *
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * Licensed 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.geronimo.gbean;
+
+import java.util.Properties;
+import java.util.HashSet;
+import java.util.Set;
+import java.rmi.MarshalledObject;
+
+import junit.framework.TestCase;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class GBeanNameTest extends TestCase {
+ private Properties props;
+
+ public void testPropertyConstruction() {
+ String domain = "testDomain";
+ props.put("prop1", "value1");
+ props.put("prop2", "value2");
+ GBeanName name = new GBeanName(domain, props);
+ assertEquals("testDomain:prop1=value1,prop2=value2", name.toString());
+ }
+
+ public void testNameConstruction() {
+ GBeanName name = new GBeanName("testDomain:prop1=value1,prop2=value2");
+ assertEquals("testDomain:prop1=value1,prop2=value2", name.toString());
+
+ name = new GBeanName("testDomain:prop2=value2,prop1=value1");
+ assertEquals("testDomain:prop2=value2,prop1=value1", name.toString());
+ }
+
+ public void testMatches() {
+ GBeanName name = new GBeanName("testDomain:prop1=value1,prop2=value2");
+ assertTrue(name.matches(null, null));
+ assertTrue(name.matches(null, props));
+ assertTrue(name.matches("testDomain", null));
+ assertTrue(name.matches("testDomain", props));
+
+ assertFalse(name.matches("test", null));
+ assertFalse(name.matches("test", props));
+
+ props.setProperty("prop1", "value2");
+ assertFalse(name.matches("testDomain", props));
+ props.setProperty("prop1", "value1");
+ assertTrue(name.matches("testDomain", props));
+ props.setProperty("prop2", "value2");
+ assertTrue(name.matches("testDomain", props));
+ props.setProperty("prop3", "value3");
+ assertFalse(name.matches("testDomain", props));
+ }
+
+ public void testInvalidNames() {
+ try {
+ new GBeanName(null);
+ fail();
+ } catch (NullPointerException e) {
+ }
+ try {
+ new GBeanName("");
+ fail();
+ } catch (IllegalArgumentException e) {
+ }
+ try {
+ new GBeanName("foo=bar");
+ fail();
+ } catch (IllegalArgumentException e) {
+ }
+ try {
+ new GBeanName("x:");
+ fail();
+ } catch (IllegalArgumentException e) {
+ }
+ try {
+ new GBeanName("x: ");
+ fail();
+ } catch (IllegalArgumentException e) {
+ }
+ try {
+ new GBeanName("x:foo");
+ fail();
+ } catch (IllegalArgumentException e) {
+ }
+ try {
+ new GBeanName("x:x=x,foo");
+ fail();
+ } catch (IllegalArgumentException e) {
+ }
+ try {
+ new GBeanName("x:x=x,").toString();
+ fail();
+ } catch (IllegalArgumentException e) {
+ }
+ try {
+ new GBeanName("x:x=x, ").toString();
+ fail();
+ } catch (IllegalArgumentException e) {
+ }
+ try {
+ new GBeanName("x:,x=x");
+ fail();
+ } catch (IllegalArgumentException e) {
+ }
+ try {
+ new GBeanName("x:x=x,,y=y");
+ fail();
+ } catch (IllegalArgumentException e) {
+ }
+ try {
+ new GBeanName("x:x=x,x=x");
+ fail();
+ } catch (IllegalArgumentException e) {
+ }
+ }
+
+ public void testEquals() {
+ GBeanName name = new GBeanName("testDomain:prop1=value1,prop2=value2");
+ assertEquals(name, name);
+ assertEquals(new GBeanName("testDomain:prop2=value2,prop1=value1"),
name);
+ assertFalse(name.equals(new
GBeanName("foo:prop1=value1,prop2=value2")));
+ assertFalse(name.equals(new GBeanName("testDomain:prop1=value1")));
+ assertFalse(name.equals(new GBeanName("testDomain:prop2=value2")));
+ assertFalse(name.equals(new GBeanName("testDomain:prop2=value2")));
+ assertFalse(name.equals(new
GBeanName("testDomain:prop1=value1,prop2=value2,prop3=value3")));
+
+ Set set = new HashSet();
+ set.add(name);
+ set.add(name);
+ assertEquals(1, set.size());
+ }
+
+ public void testSerialization() throws Exception {
+ GBeanName name = new GBeanName("testDomain:prop1=value1,prop2=value2");
+ MarshalledObject o = new MarshalledObject(name);
+ GBeanName name2 = (GBeanName) o.get();
+ assertEquals(name, name2);
+ }
+
+ protected void setUp() throws Exception {
+ props = new Properties();
+ }
+}