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 }