PageRenderTime 30ms CodeModel.GetById 16ms app.highlight 10ms RepoModel.GetById 1ms app.codeStats 0ms

/hudson-core/src/main/java/hudson/util/DescribableList.java

http://github.com/hudson/hudson
Java | 257 lines | 134 code | 27 blank | 96 comment | 9 complexity | b88e385eeede47622a0d1ce6852b9424 MD5 | raw file
  1/*
  2 * The MIT License
  3 * 
  4 * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi
  5 * 
  6 * Permission is hereby granted, free of charge, to any person obtaining a copy
  7 * of this software and associated documentation files (the "Software"), to deal
  8 * in the Software without restriction, including without limitation the rights
  9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 10 * copies of the Software, and to permit persons to whom the Software is
 11 * furnished to do so, subject to the following conditions:
 12 * 
 13 * The above copyright notice and this permission notice shall be included in
 14 * all copies or substantial portions of the Software.
 15 * 
 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 22 * THE SOFTWARE.
 23 */
 24package hudson.util;
 25
 26import com.thoughtworks.xstream.converters.Converter;
 27import com.thoughtworks.xstream.converters.MarshallingContext;
 28import com.thoughtworks.xstream.converters.UnmarshallingContext;
 29import com.thoughtworks.xstream.converters.collections.AbstractCollectionConverter;
 30import com.thoughtworks.xstream.io.HierarchicalStreamReader;
 31import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
 32import com.thoughtworks.xstream.mapper.Mapper;
 33import hudson.model.AbstractProject;
 34import hudson.model.DependecyDeclarer;
 35import hudson.model.DependencyGraph;
 36import hudson.model.Describable;
 37import hudson.model.Descriptor;
 38import hudson.model.Descriptor.FormException;
 39import hudson.model.Saveable;
 40import net.sf.json.JSONObject;
 41import org.kohsuke.stapler.StaplerRequest;
 42
 43import java.io.IOException;
 44import java.util.ArrayList;
 45import java.util.Collection;
 46import java.util.List;
 47import java.util.Map;
 48
 49/**
 50 * Persisted list of {@link Describable}s with some operations specific
 51 * to {@link Descriptor}s.
 52 *
 53 * <p>
 54 * This class allows multiple instances of the same descriptor. Some clients
 55 * use this semantics, while other clients use it as "up to one instance per
 56 * one descriptor" model.
 57 *
 58 * Some of the methods defined in this class only makes sense in the latter model,
 59 * such as {@link #remove(Descriptor)}.
 60 *
 61 * @author Kohsuke Kawaguchi
 62 */
 63public class DescribableList<T extends Describable<T>, D extends Descriptor<T>> extends PersistedList<T> {
 64    protected DescribableList() {
 65    }
 66
 67    /**
 68     * @deprecated since 2008-08-15.
 69     *      Use {@link #DescribableList(Saveable)}
 70     */
 71    public DescribableList(Owner owner) {
 72        setOwner(owner);
 73    }
 74
 75    public DescribableList(Saveable owner) {
 76        setOwner(owner);
 77    }
 78
 79    public DescribableList(Saveable owner, Collection<? extends T> initialList) {
 80        super(initialList);
 81        setOwner(owner);
 82    }
 83
 84    /**
 85     * @deprecated since 2008-08-15.
 86     *      Use {@link #setOwner(Saveable)}
 87     */
 88    public void setOwner(Owner owner) {
 89        this.owner = owner;
 90    }
 91
 92    /**
 93     * Removes all instances of the same type, then add the new one.
 94     */
 95    public void replace(T item) throws IOException {
 96        removeAll((Class)item.getClass());
 97        data.add(item);
 98        onModified();
 99    }
100
101    public T get(D descriptor) {
102        for (T t : data)
103            if(t.getDescriptor()==descriptor)
104                return t;
105        return null;
106    }
107
108    public boolean contains(D d) {
109        return get(d)!=null;
110    }
111
112    public void remove(D descriptor) throws IOException {
113        for (T t : data) {
114            if(t.getDescriptor()==descriptor) {
115                data.remove(t);
116                onModified();
117                return;
118            }
119        }
120    }
121
122    /**
123     * Creates a detached map from the current snapshot of the data, keyed from a descriptor to an instance.
124     */
125    @SuppressWarnings("unchecked")
126    public Map<D,T> toMap() {
127        return (Map)Descriptor.toMap(data);
128    }
129
130    /**
131     * Rebuilds the list by creating a fresh instances from the submitted form.
132     * <p/>
133     * <p/>
134     * This method is almost always used by the owner.
135     * This method does not invoke the save method.
136     *
137     * @param json Structured form data that includes the data for nested descriptor list.
138     * @deprecated as of 2.2.0,
139     *             use {@link DescribableListUtil#buildFromJson(hudson.model.Saveable, org.kohsuke.stapler.StaplerRequest, net.sf.json.JSONObject, java.util.List)}
140     */
141    public void rebuild(StaplerRequest req, JSONObject json, List<? extends Descriptor<T>> descriptors)
142        throws FormException, IOException {
143        List<T> newList = new ArrayList<T>();
144
145        for (Descriptor<T> d : descriptors) {
146            String name = d.getJsonSafeClassName();
147            if (json.has(name)) {
148                T instance = d.newInstance(req, json.getJSONObject(name));
149                newList.add(instance);
150            }
151        }
152
153        replaceBy(newList);
154    }
155
156    /**
157     * @deprecated as of 1.271
158     *      Use {@link #rebuild(StaplerRequest, JSONObject, List)} instead.
159     */
160    public void rebuild(StaplerRequest req, JSONObject json, List<? extends Descriptor<T>> descriptors, String prefix) throws FormException, IOException {
161        rebuild(req,json,descriptors);
162    }
163
164    /**
165     * Rebuilds the list by creating a fresh instances from the submitted form.
166     * <p/>
167     * This version works with the the &lt;f:hetero-list> UI tag, where the user
168     * is allowed to create multiple instances of the same descriptor. Order is also
169     * significant.
170     *
171     * @deprecated as of 2.2.0,
172     *             use {@link DescribableListUtil#buildFromHetero(hudson.model.Saveable, org.kohsuke.stapler.StaplerRequest, net.sf.json.JSONObject, String, java.util.Collection)}
173     *             or {@link Descriptor#newInstancesFromHeteroList(org.kohsuke.stapler.StaplerRequest, net.sf.json.JSONObject, String, java.util.Collection)}
174     */
175    public void rebuildHetero(StaplerRequest req,
176                              JSONObject formData,
177                              Collection<? extends Descriptor<T>> descriptors,
178                              String key)
179        throws FormException, IOException {
180        replaceBy(Descriptor.newInstancesFromHeteroList(req, formData, key, descriptors));
181    }
182
183    /**
184     * Picks up {@link DependecyDeclarer}s and allow it to build dependencies.
185     */
186    public void buildDependencyGraph(AbstractProject owner,DependencyGraph graph) {
187        for (Object o : this) {
188            if (o instanceof DependecyDeclarer) {
189                DependecyDeclarer dd = (DependecyDeclarer) o;
190                dd.buildDependencyGraph(owner,graph);
191            }
192        }
193    }
194
195/*
196    The following two seemingly pointless method definitions are necessary to produce
197    backward compatible binary signatures. Without this we only get
198    get(Ljava/lang/Class;)Ljava/lang/Object; from PersistedList where we need
199    get(Ljava/lang/Class;)Lhudson/model/Describable;
200 */
201    public <U extends T> U get(Class<U> type) {
202        return super.get(type);
203    }
204
205    public T[] toArray(T[] array) {
206        return super.toArray(array);
207    }
208
209    /**
210     * @deprecated since 2008-08-15.
211     *      Just implement {@link Saveable}.
212     */
213    public interface Owner extends Saveable {
214    }
215
216    /**
217     * {@link Converter} implementation for XStream.
218     *
219     * Serializaion form is compatible with plain {@link List}.
220     */
221    public static class ConverterImpl extends AbstractCollectionConverter {
222        CopyOnWriteList.ConverterImpl copyOnWriteListConverter;
223
224        public ConverterImpl(Mapper mapper) {
225            super(mapper);
226            copyOnWriteListConverter = new CopyOnWriteList.ConverterImpl(mapper());
227        }
228
229        public boolean canConvert(Class type) {
230            // handle subtypes in case the onModified method is overridden.
231            return DescribableList.class.isAssignableFrom(type);
232        }
233
234        public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
235            for (Object o : (DescribableList) source)
236                writeItem(o, context, writer);
237        }
238
239        public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
240            CopyOnWriteList core = copyOnWriteListConverter.unmarshal(reader, context);
241
242            try {
243                DescribableList r = (DescribableList)context.getRequiredType().newInstance();
244                r.data.replaceBy(core);
245                return r;
246            } catch (InstantiationException e) {
247                InstantiationError x = new InstantiationError();
248                x.initCause(e);
249                throw x;
250            } catch (IllegalAccessException e) {
251                IllegalAccessError x = new IllegalAccessError();
252                x.initCause(e);
253                throw x;
254            }
255        }
256    }
257}