001 /*
002 * JBoss, Home of Professional Open Source.
003 * Copyright 2008, Red Hat Middleware LLC, and individual contributors
004 * as indicated by the @author tags. See the copyright.txt file in the
005 * distribution for a full listing of individual contributors.
006 *
007 * This is free software; you can redistribute it and/or modify it
008 * under the terms of the GNU Lesser General Public License as
009 * published by the Free Software Foundation; either version 2.1 of
010 * the License, or (at your option) any later version.
011 *
012 * This software is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * You should have received a copy of the GNU Lesser General Public
018 * License along with this software; if not, write to the Free
019 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021 */
022 package org.jboss.dna.common.component;
023
024 import java.util.ArrayList;
025 import java.util.Collections;
026 import java.util.List;
027 import net.jcip.annotations.Immutable;
028 import org.jboss.dna.common.CommonI18n;
029 import org.jboss.dna.common.util.CheckArg;
030 import org.jboss.dna.common.util.ClassUtil;
031
032 /**
033 * @author Randall Hauch
034 */
035 @Immutable
036 public class ComponentConfig implements Comparable<ComponentConfig> {
037
038 private final String name;
039 private final String description;
040 private final String componentClassname;
041 private final List<String> classpath;
042 private final long timestamp;
043
044 /**
045 * Create a component configuration.
046 * @param name the name of the configuration, which is considered to be a unique identifier
047 * @param description the description
048 * @param classname the name of the Java class used for the component
049 * @param classpath the optional classpath (defined in a way compatible with a {@link ClassLoaderFactory}
050 * @throws IllegalArgumentException if the name is null, empty or blank, or if the classname is null, empty or not a valid
051 * Java classname
052 */
053 public ComponentConfig( String name, String description, String classname, String... classpath ) {
054 this(name, description, System.currentTimeMillis(), classname, classpath);
055 }
056
057 /**
058 * Create a component configuration.
059 * @param name the name of the configuration, which is considered to be a unique identifier
060 * @param description the description
061 * @param timestamp the timestamp that this component was last changed
062 * @param classname the name of the Java class used for the component
063 * @param classpath the optional classpath (defined in a way compatible with a {@link ClassLoaderFactory}
064 * @throws IllegalArgumentException if the name is null, empty or blank, or if the classname is null, empty or not a valid
065 * Java classname
066 */
067 public ComponentConfig( String name, String description, long timestamp, String classname, String... classpath ) {
068 CheckArg.isNotEmpty(name, "name");
069 this.name = name.trim();
070 this.description = description != null ? description.trim() : "";
071 this.componentClassname = classname;
072 this.classpath = buildList(classpath);
073 this.timestamp = timestamp;
074 // Check the classname is a valid classname ...
075 if (!ClassUtil.isFullyQualifiedClassname(classname)) {
076 throw new IllegalArgumentException(CommonI18n.componentClassnameNotValid.text(classname, name));
077 }
078 }
079
080 /* package */static List<String> buildList( String... classpathElements ) {
081 List<String> classpath = null;
082 if (classpathElements != null) {
083 classpath = new ArrayList<String>();
084 for (String classpathElement : classpathElements) {
085 if (!classpath.contains(classpathElement)) classpath.add(classpathElement);
086 }
087 classpath = Collections.unmodifiableList(classpath);
088 } else {
089 classpath = Collections.emptyList(); // already immutable
090 }
091 return classpath;
092 }
093
094 /**
095 * Get the name of this component.
096 * @return the component name; never null, empty or blank
097 */
098 public String getName() {
099 return this.name;
100 }
101
102 /**
103 * Get the description for this component
104 * @return the description
105 */
106 public String getDescription() {
107 return this.description;
108 }
109
110 /**
111 * Get the fully-qualified name of the Java class used for instances of this component
112 * @return the Java class name of this component; never null or empty and always a valid Java class name
113 */
114 public String getComponentClassname() {
115 return this.componentClassname;
116 }
117
118 /**
119 * Get the classpath defined in terms of strings compatible with a {@link ClassLoaderFactory}.
120 * @return the classpath; never null but possibly empty
121 */
122 public List<String> getComponentClasspath() {
123 return this.classpath;
124 }
125
126 /**
127 * Get the classpath defined as an array of strings compatible with a {@link ClassLoaderFactory}.
128 * @return the classpath as an array; never null but possibly empty
129 */
130 public String[] getComponentClasspathArray() {
131 return this.classpath.toArray(new String[this.classpath.size()]);
132 }
133
134 /**
135 * Get the system timestamp when this configuration object was created.
136 * @return the timestamp
137 */
138 public long getTimestamp() {
139 return this.timestamp;
140 }
141
142 /**
143 * {@inheritDoc}
144 */
145 public int compareTo( ComponentConfig that ) {
146 if (that == this) return 0;
147 int diff = this.getName().compareToIgnoreCase(that.getName());
148 if (diff != 0) return diff;
149 diff = (int)(this.getTimestamp() - that.getTimestamp());
150 return diff;
151 }
152
153 /**
154 * {@inheritDoc}
155 */
156 @Override
157 public int hashCode() {
158 return this.getName().hashCode();
159 }
160
161 /**
162 * {@inheritDoc}
163 */
164 @Override
165 public boolean equals( Object obj ) {
166 if (obj == this) return true;
167 if (obj instanceof ComponentConfig) {
168 ComponentConfig that = (ComponentConfig)obj;
169 if (!this.getClass().equals(that.getClass())) return false;
170 return this.getName().equalsIgnoreCase(that.getName());
171 }
172 return false;
173 }
174
175 /**
176 * Determine whether this component has changed with respect to the supplied component. This method basically checks all
177 * attributes, whereas {@link #equals(Object) equals} only checks the {@link #getClass() type} and {@link #getName()}.
178 * @param component the component to be compared with this one
179 * @return true if this componet and the supplied component have some changes, or false if they are exactly equivalent
180 * @throws IllegalArgumentException if the supplied component reference is null or is not the same {@link #getClass() type} as
181 * this object
182 */
183 public boolean hasChanged( ComponentConfig component ) {
184 CheckArg.isNotNull(component, "component");
185 CheckArg.isInstanceOf(component, this.getClass(), "component");
186 if (!this.getName().equalsIgnoreCase(component.getName())) return true;
187 if (!this.getDescription().equals(component.getDescription())) return true;
188 if (!this.getComponentClassname().equals(component.getComponentClassname())) return true;
189 if (!this.getComponentClasspath().equals(component.getComponentClasspath())) return true;
190 return false;
191 }
192
193 }