View Javadoc

1   /*
2   Karma core - Core of the Karma application
3   Copyright (C) 2004  Toolforge <www.toolforge.nl>
4   
5   This library is free software; you can redistribute it and/or
6   modify it under the terms of the GNU Lesser General Public
7   License as published by the Free Software Foundation; either
8   version 2.1 of the License, or (at your option) any later version.
9   
10  This library is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  Lesser General Public License for more details.
14  
15  You should have received a copy of the GNU Lesser General Public
16  License along with this library; if not, write to the Free Software
17  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19  package nl.toolforge.karma.core.module;
20  
21  import nl.toolforge.karma.core.Version;
22  import nl.toolforge.karma.core.location.Location;
23  import nl.toolforge.karma.core.module.template.ModuleLayoutTemplate;
24  import nl.toolforge.karma.core.vc.AuthenticationException;
25  import nl.toolforge.karma.core.vc.Authenticator;
26  import nl.toolforge.karma.core.vc.DevelopmentLine;
27  import nl.toolforge.karma.core.vc.VersionControlException;
28  
29  import java.io.File;
30  import java.util.Set;
31  import java.util.regex.PatternSyntaxException;
32  
33  
34  /***
35   * <p>A module is a collection of files, representing some block of functionality. This definition is probably highly
36   * subjective, but for Karma, that's what it is. A module is part of a container, called a
37   * <code>Manifest</code>. System's theory tells us that a system is separated into subsystems. Well, that's what we
38   * do in the Karma context as well. An application system consists of one or more (generally more) modules.</p>
39   *
40   * <p>Karma <code>Module</code>s are maintained in a version management system and grouped together in a
41   * <code>Manifest</code>. The manifest is managing the modules.</p>
42   *
43   * @author D.A. Smedes
44   * @version $Id: Module.java,v 1.1 2004/11/10 22:25:11 hippe Exp $
45   */
46  public interface Module {
47  
48    /***
49     * <code>UNKNOWN</code> applies to module which have no local presence. The actual type can only be determined when
50     * the <code>module-descriptor.xml</code> file is available, which is the case after a checkout of the module.
51     */
52    public static final Type UNKNOWN = new Type("UNKNOWN");
53    /***
54     * Represents <code>&lt;type&gt;LIBRARY_MODULE&lt;/type&gt;</code>.
55     */
56    public static final Type LIBRARY_MODULE = new Type("LIBRARY-MODULE");
57    /***
58     * Represents <code>&lt;type&gt;JAVA_SOURCE_MODULE&lt;/type&gt;</code>.
59     */
60    public static final Type JAVA_SOURCE_MODULE = new Type("JAVA-SOURCE-MODULE");
61    /***
62     * Represents <code>&lt;type&gt;JAVA_WEB_APPLICATION&lt;/type&gt;</code>.
63     */
64    public static final Type JAVA_WEB_APPLICATION = new Type("JAVA-WEB-APPLICATION");
65    /***
66     * Represents <code>&lt;type&gt;OTHER-MODULE&lt;/type&gt;</code>.
67     */
68    public static final Type OTHER_MODULE = new Type("OTHER-MODULE");
69  
70    /***
71     * Represents <code>&lt;type&gt;JAVA_ENTERPRISE_APPLICATION&lt;/type&gt;</code>.
72     */
73    public static final Type JAVA_ENTERPRISE_APPLICATION = new Type("JAVA-ENTERPRISE-APPLICATION");
74  
75    public static final State WORKING = new State("WORKING");
76    public static final State DYNAMIC = new State("DYNAMIC");
77    public static final State STATIC = new State("STATIC");
78  
79    /***
80     * String identifying the file name for the module descriptor.
81     */
82    public static final String MODULE_DESCRIPTOR = "module-descriptor.xml";
83  
84    /***
85     * Retrieves a modules' name, the <code>name</code> attribute of the module in the manifest XML file.
86     *
87     * @return The modules' name.
88     */
89    public String getName();
90  
91    /***
92     * Determines the type of the module. This is only possible when the module is checked out locally.
93     *
94     * @return The type of the module (see constants defined in <code>Module</code>).
95     */
96    public Type getType() throws ModuleTypeException;
97  
98    /***
99     * Returns the <code>Location</code> instance, which is derived from the <code>location</code>-attribute.
100    */
101   public Location getLocation();
102 
103   /***
104    * A module has a base directory, which is relative to the manifest that requires it. When the manifest is loaded, the
105    * base directory can be set.
106    *
107    * @param baseDir The base directory of the module relative to the active manifest.
108    */
109   public void setBaseDir(File baseDir);
110 
111   /***
112    * The base directory of the module relative to the active manifest.
113    *
114    * @return The base directory of the module relative to the active manifest.
115    */
116   public File getBaseDir();
117 
118 //  public void setCheckoutDir(File checkoutDir);
119 
120 //  public File getCheckoutDir();
121   
122   /***
123    * Returns the <code>PatchLine</code> for this module, if the module matches the correct criteria as specified in
124    * {@link #markPatchLine(boolean)}.
125    *
126    * @return <code>null</code> if a PatchLine does not exist for this module, otherwise the <code>PatchLine</code>
127    *   instance for this module.
128    * @see #markPatchLine(boolean)
129    */
130   public DevelopmentLine getPatchLine();
131 
132   /***
133    * Marks this module as being developed in a <code>PatchLine</code>. This can only happen when the manifest in which
134    * the module is used is a <code>ReleaseManifest</code> and the module has a <code>STATIC</code> state. When the
135    * manifest is loaded, this method will be called when the module matches the criteria.
136    */
137   public void markPatchLine(boolean mark);
138 
139   public boolean hasPatchLine();
140 
141   /***
142    * Checks if the module - within the current manifest - has development line configuration. When the manifest is
143    * a <code>ReleaseManifest</code>, this is true when a <code>PatchLine</code> exists. When the manifest is a
144    * <code>DevelopmentManifest</code>, this method returns false, as this feature is not supported.
145    *
146    * @return
147    */
148   public boolean hasDevelopmentLine();
149 
150   /***
151    * Marks this modules as being developed in a <code>DevelopmentLine</code>. This feature is NOT supported as yet.
152    */
153   public void markDevelopmentLine(boolean mark);
154 
155   /***
156    * If a module has a &lt;version&gt;-attribute, this method returns a Version instance representing the version
157    * number of the module.
158    *
159    * @return The version of the module if it has one.
160    */
161   public Version getVersion();
162 
163   /***
164    * If the module element in the manifest contains a <code>version</code> attribute, this method will return the
165    * value of that attribute.
166    *
167    * @return The module version, or <code>N/A</code>, when no version number exists.
168    */
169   public String getVersionAsString();
170 
171   /***
172    * Checks if a module has a &lt;version&gt;-attribute.
173    *
174    * @return <ode>true</code> if the module has a &lt;version&gt;-attribute or <code>false</code> if it hasn't.
175    */
176   public boolean hasVersion();
177 
178   /***
179    * Gets a <code>Set</code> of <code>ModuleDependency</code> objects. This method should return an empty set if no
180    * dependencies have been specified. Dependencies are not checked to be available. 
181    *
182    * @return A <code>Set</code> containing all dependencies as <code>ModuleDependency</code> objects.
183    */
184   public Set getDependencies();
185 
186   /***
187    * Returns the correct layout template for the module.
188    *
189    * @return A <code>ModuleLayoutTemplate</code> for the specific module type.
190    */
191   public ModuleLayoutTemplate getLayoutTemplate();
192 
193   public void createRemote(Authenticator authenticator, String createComment) throws VersionControlException, AuthenticationException ;
194 
195   /***
196    * Inner class representing the type of the module, which is determined at runtime by reading the
197    * <code>module-descriptor.xml</code> file from the module base directory.
198    *
199    * @author D.A. Smedes
200    */
201   final class Type {
202 
203     private String type = null;
204     private String shortType = null;
205 
206     public Type() {}
207 
208     private Type(String type) {
209       this.type = type;
210     }
211 
212     // todo think of better shortcuts for these types.
213     public void setType(String type) {
214       if ("src".equals(type) || JAVA_SOURCE_MODULE.getType().equals(type)) {
215         this.type = JAVA_SOURCE_MODULE.getType();
216         shortType = "src";
217       } else if ("lib".equals(type) || LIBRARY_MODULE.getType().equals(type)) {
218         this.type = LIBRARY_MODULE.getType();
219         shortType = "lib";
220       } else if ("webapp".equals(type) || JAVA_WEB_APPLICATION.getType().equals(type)) {
221         this.type = JAVA_WEB_APPLICATION.getType();
222         shortType = "webapp";
223       } else if ("eapp".equals(type) || JAVA_ENTERPRISE_APPLICATION.getType().equals(type)) {
224         this.type = JAVA_ENTERPRISE_APPLICATION.getType();
225         shortType = "eapp";
226       } else if ("other".equals(type) || OTHER_MODULE.getType().equals(type)) {
227         this.type = OTHER_MODULE.getType();
228         shortType = "other";
229       } else {
230         throw new IllegalArgumentException("Type must be 'src', 'lib', 'webapp', 'eapp' or 'other'.");
231       }
232     }
233 
234     public String getType() {
235       return type;
236     }
237 
238     public String getShortType() {
239       return shortType;
240     }
241 
242     public String toString() {
243       return getType();
244     }
245     
246     public int hashCode() {
247       return type.hashCode();
248     }
249 
250     public boolean equals(Object o) {
251       if (o instanceof Type) {
252         if (((Type) o).type.equals(type)) {
253           return true;
254         } else {
255           return false;
256         }
257       }
258       return false;
259     }
260   }
261 
262   /***
263    * <p>Inner class representing the 'state' of a module. Three states exist at the moment : <code>WORKING</code>,
264    * <code>STATIC</code> and <code>DYNAMIC</code>.
265    * <p/>
266    *
267    * <ul>
268    *   <li/><code>WORKING</code> means that a developer wants to develop on the module; add code, remove code etc. The
269    *        local copy of the module will be updated to the reflect the latest versions of files in a particular
270    *        branch. <code>WORKING</code> state also implies that a developer can promote a module so that manifests
271    *        that have the module in a <code>DYNAMIC</code> state, can choose to upgrade their manifest to the latest
272    *        (stable) version of the module.
273    *   <li/><code>DYNAMNIC</code> means that a developer is not interested in the HEAD of a development line, but only
274    *        in stable versions of the module.
275    *   <li/><code>STATIC</code> means that a developer wants to use a fixed version of the module in the manifest.
276    * </ul>
277    *
278    * @author D.A. Smedes
279    */
280   final class State {
281 
282     // todo unit test should be written
283 
284     private String state = null;
285 
286     /***
287      * Constructor. Initializes the <code>State</code> instance with the correct state string.
288      *
289      * @param stateString
290      */
291     public State(String stateString) {
292 
293       if (!stateString.matches("WORKING|DYNAMIC|STATIC|UNDEFINED")) {
294         throw new PatternSyntaxException(
295             "Pattern mismatch for 'state'; pattern must match 'WORKING|DYNAMIC|STATIC|UNDEFINED'", stateString, -1);
296       }
297       this.state = stateString;
298     }
299 
300     /***
301      * Gets the string representation of this state object.
302      *
303      * @return A <code>String</code> representation of this state object.
304      */
305     public String toString() {
306       return state;
307     }
308 
309     public int hashCode() {
310       return state.hashCode();
311     }
312 
313     /***
314      * Checks equality of one <code>State</code> instance to this <code>State</code> instance. Instances are equal
315      * when their state strings are equal.
316      *
317      * @param o An object instance that must be checked for equality with this <code>State</code> instance.
318      * @return <code>true</code> if this <code>State</code> instance equals <code>o</code>, otherwise
319      *         <code>false</code>.
320      */
321     public boolean equals(Object o) {
322 
323       if (o instanceof State) {
324         if (o.toString().equals(this.toString())) {
325           return true;
326         } else {
327           return false;
328         }
329       }
330       return false;
331     }
332 
333     /***
334      * Returns the filename for this state on disk (generally something like <code>.WORKING</code> or
335      * <code>.STATIC</code>.
336      *
337      * @return
338      */
339     public String getHiddenFileName() {
340       return "." + state;
341     }
342   }
343 }