KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > hudson > model > Descriptor


1 package hudson.model;
2
3 import hudson.XmlFile;
4 import hudson.scm.CVSSCM;
5 import org.kohsuke.stapler.StaplerRequest;
6
7 import javax.servlet.http.HttpServletRequest JavaDoc;
8 import java.io.File JavaDoc;
9 import java.io.IOException JavaDoc;
10 import java.util.ArrayList JavaDoc;
11 import java.util.LinkedHashMap JavaDoc;
12 import java.util.List JavaDoc;
13 import java.util.Map JavaDoc;
14 import java.util.logging.Level JavaDoc;
15 import java.util.logging.Logger JavaDoc;
16
17 /**
18  * Metadata about a configurable instance.
19  *
20  * <p>
21  * {@link Descriptor} is an object that has metadata about a {@link Describable}
22  * object, and also serves as a factory (in a way this relationship is similar
23  * to {@link Object}/{@link Class} relationship.
24  *
25  * A {@link Descriptor}/{@link Describable}
26  * combination is used throughout in Hudson to implement a
27  * configuration/extensibility mechanism.
28  *
29  * <p>
30  * For example, Take the CVS support as an example, which is implemented
31  * in {@link CVSSCM} class. Whenever a job is configured with CVS, a new
32  * {@link CVSSCM} instance is created with the per-job configuration
33  * information. This instance gets serialized to XML, and this instance
34  * will be called to perform CVS operations for that job. This is the job
35  * of {@link Describable} &mdash; each instance represents a specific
36  * configuration of the CVS support (branch, CVSROOT, etc.)
37  *
38  * <p>
39  * For Hudson to create such configured {@link CVSSCM} instance, Hudson
40  * needs another object that captures the metadata of {@link CVSSCM},
41  * and that is what a {@link Descriptor} is for. {@link CVSSCM} class
42  * has a singleton descriptor, and this descriptor helps render
43  * the configuration form, remember system-wide configuration (such as
44  * where <tt>cvs.exe</tt> is), and works as a factory.
45  *
46  * <p>
47  * {@link Descriptor} also usually have its associated views.
48  *
49  *
50  * <h2>Persistence</h2>
51  * <p>
52  * {@link Descriptor} can persist data just by storing them in fields.
53  * However, it is the responsibility of the derived type to properly
54  * invoke {@link #save()} and {@link #load()}.
55  *
56  * @author Kohsuke Kawaguchi
57  * @see Describable
58  */

59 public abstract class Descriptor<T extends Describable<T>> {
60     /**
61      * Up to Hudson 1.61 this was used as the primary persistence mechanism.
62      * Going forward Hudson simply persists all the non-transient fields
63      * of {@link Descriptor}, just like others, so this is pointless.
64      *
65      * @deprecated
66      */

67     @Deprecated JavaDoc
68     private transient Map JavaDoc<String JavaDoc,Object JavaDoc> properties;
69
70     /**
71      * The class being described by this descriptor.
72      */

73     public transient final Class JavaDoc<? extends T> clazz;
74
75     protected Descriptor(Class JavaDoc<? extends T> clazz) {
76         this.clazz = clazz;
77         // doing this turns out to be very error prone,
78
// as field initializers in derived types will override values.
79
// load();
80
}
81
82     /**
83      * Human readable name of this kind of configurable object.
84      */

85     public abstract String JavaDoc getDisplayName();
86
87     /**
88      * Creates a configured instance from the submitted form.
89      *
90      * <p>
91      * Hudson only invokes this method when the user wants an instance of <tt>T</tt>.
92      * So there's no need to check that in the implementation.
93      *
94      * @param req
95      * Always non-null. This object includes all the submitted form values.
96      *
97      * @throws FormException
98      * Signals a problem in the submitted form.
99      */

100     public abstract T newInstance(StaplerRequest req) throws FormException;
101
102     /**
103      * Returns the resource path to the help screen HTML, if any.
104      */

105     public String JavaDoc getHelpFile() {
106         return "";
107     }
108
109     /**
110      * Checks if the given object is created from this {@link Descriptor}.
111      */

112     public final boolean isInstance( T instance ) {
113         return clazz.isInstance(instance);
114     }
115
116     /**
117      * @deprecated
118      * As of 1.64. Use {@link #configure(StaplerRequest)}.
119      */

120     @Deprecated JavaDoc
121     public boolean configure( HttpServletRequest JavaDoc req ) throws FormException {
122         return true;
123     }
124
125     /**
126      * Invoked when the global configuration page is submitted.
127      *
128      * Can be overriden to store descriptor-specific information.
129      *
130      * @return false
131      * to keep the client in the same config page.
132      */

133     public boolean configure( StaplerRequest req ) throws FormException {
134         // compatibility
135
return configure( (HttpServletRequest JavaDoc) req );
136     }
137
138     public String JavaDoc getConfigPage() {
139         return getViewPage(clazz, "config.jelly");
140     }
141
142     public String JavaDoc getGlobalConfigPage() {
143         return getViewPage(clazz, "global.jelly");
144     }
145
146     protected final String JavaDoc getViewPage(Class JavaDoc<?> clazz, String JavaDoc pageName) {
147         return '/'+ clazz.getName().replace('.','/').replace('$','/')+"/"+ pageName;
148     }
149
150
151     /**
152      * Saves the configuration info to the disk.
153      */

154     protected synchronized void save() {
155         try {
156             getConfigFile().write(this);
157         } catch (IOException JavaDoc e) {
158             LOGGER.log(Level.WARNING, "Failed to save "+getConfigFile(),e);
159         }
160     }
161
162     /**
163      * Loads the data from the disk into this object.
164      *
165      * <p>
166      * The constructor of the derived class must call this method.
167      * (If we do that in the base class, the derived class won't
168      * get a chance to set default values.)
169      */

170     protected synchronized void load() {
171         XmlFile file = getConfigFile();
172         if(!file.exists())
173             return;
174
175         try {
176             Object JavaDoc o = file.unmarshal(this);
177             if(o instanceof Map JavaDoc) {
178                 // legacy format
179
@SuppressWarnings JavaDoc("unchecked")
180                 Map JavaDoc<String JavaDoc,Object JavaDoc> _o = (Map JavaDoc) o;
181                 convert(_o);
182                 save(); // convert to the new format
183
}
184         } catch (IOException JavaDoc e) {
185             LOGGER.log(Level.WARNING, "Failed to load "+file, e);
186         }
187     }
188
189     /**
190      * {@link Descriptor}s that has existed &lt;= 1.61 needs to
191      * be able to read in the old configuration in a property bag
192      * and reflect that into the new layout.
193      */

194     protected void convert(Map JavaDoc<String JavaDoc, Object JavaDoc> oldPropertyBag) {
195     }
196
197     private XmlFile getConfigFile() {
198         return new XmlFile(new File(Hudson.getInstance().getRootDir(),clazz.getName()+".xml"));
199     }
200
201     // to work around warning when creating a generic array type
202
public static <T> T[] toArray( T... values ) {
203         return values;
204     }
205
206     public static <T> List JavaDoc<T> toList( T... values ) {
207         final ArrayList JavaDoc<T> r = new ArrayList JavaDoc<T>();
208         for (T v : values)
209             r.add(v);
210         return r;
211     }
212
213     public static <T extends Describable<T>>
214     Map JavaDoc<Descriptor<T>,T> toMap(Iterable JavaDoc<T> describables) {
215         Map JavaDoc<Descriptor<T>,T> m = new LinkedHashMap JavaDoc<Descriptor<T>,T>();
216         for (T d : describables) {
217             m.put(d.getDescriptor(),d);
218         }
219         return m;
220     }
221
222     public static final class FormException extends Exception JavaDoc {
223         private final String JavaDoc formField;
224
225         public FormException(String JavaDoc message, String JavaDoc formField) {
226             super(message);
227             this.formField = formField;
228         }
229
230         public FormException(String JavaDoc message, Throwable JavaDoc cause, String JavaDoc formField) {
231             super(message, cause);
232             this.formField = formField;
233         }
234
235         public FormException(Throwable JavaDoc cause, String JavaDoc formField) {
236             super(cause);
237             this.formField = formField;
238         }
239
240         /**
241          * Which form field contained an error?
242          */

243         public String JavaDoc getFormField() {
244             return formField;
245         }
246     }
247
248     private static final Logger JavaDoc LOGGER = Logger.getLogger(Descriptor.class.getName());
249 }
250
Popular Tags