View Javadoc

1   /**
2    * Copyright 2005-2007 the original author or authors.
3    *
4    * Licensed under the Gnu General Pubic License, Version 2.0 (the
5    * "License"); you may not use this file except in compliance with
6    * the License. You may obtain a copy of the License at
7    *
8    *      http://www.opensource.org/licenses/gpl-license.php
9    *
10   * This program 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.
13   * See the Gnu General Public License for more details.
14   */
15  package org.figure8.join.businessfacades.artifact;
16  
17  import org.figure8.join.core.DuplicateEntityException;
18  import org.figure8.join.core.InvalidParameterException;
19  import org.figure8.join.core.InfrastructureException;
20  import org.figure8.join.services.vcs.VCSAccessor;
21  import org.figure8.join.services.vcs.VCSAccessException;
22  import org.figure8.join.services.repository.Repository;
23  import org.figure8.join.services.repository.RepositoryException;
24  import org.figure8.join.businessobjects.commons.Release;
25  import org.figure8.join.businessobjects.artifact.Assembly;
26  import org.figure8.join.businessobjects.artifact.Component;
27  import org.figure8.join.businessobjects.artifact.Deliverable;
28  import org.figure8.join.businessobjects.artifact.ComponentType;
29  import org.figure8.join.businessobjects.artifact.DeliverableType;
30  import org.figure8.join.businessobjects.artifact.persistence.ComponentDao;
31  import org.figure8.join.businessobjects.artifact.persistence.DeliverableDao;
32  import org.figure8.join.businessobjects.artifact.persistence.ComponentTypeDao;
33  import org.figure8.join.businessobjects.artifact.persistence.DeliverableTypeDao;
34  import org.figure8.join.businessfacades.reporting.EventPublicationManager;
35  import org.figure8.join.util.LogUtil;
36  
37  import org.apache.commons.logging.Log;
38  
39  import java.io.File;
40  import java.io.InputStream;
41  import java.util.List;
42  /**
43   * This is the default implementation of {@link ArtifactManager}.
44   * @author <a href="mailto:laurent.broudoux@free.fr">Laurent Broudoux</a>
45   * @version $Revision: 1.3 $
46   */
47  public class DefaultArtifactManager implements ArtifactManager{
48  
49     // Static -------------------------------------------------------------------
50  
51     /** Get a commons logger... */
52     private static final Log log = LogUtil.getLog(DefaultArtifactManager.class);
53  
54  
55     // Attributes ---------------------------------------------------------------
56  
57     /** Component data access object */
58     protected ComponentDao componentDao = null;
59     /** Deliverable data access object */
60     protected DeliverableDao deliverableDao = null;
61     /** Component type data access object */
62     protected ComponentTypeDao componentTypeDao = null;
63     /** Deliverable type data access object */
64     protected DeliverableTypeDao deliverableTypeDao = null;
65     /** The event publication manager implementation for reporting events */
66     protected EventPublicationManager publicationManager = null;
67  
68     /** The Repository implementation to use for storing deliverables */
69     protected Repository deliverablesRepository = null;
70  
71  
72     // Constructors -------------------------------------------------------------
73     
74     /** Creates a new instance of DefaultArtifactManager */
75     public DefaultArtifactManager(){
76     }
77     
78     
79     // Public -------------------------------------------------------------------
80  
81     /** @param dao A Component data access object */
82     public void setComponentDao(ComponentDao dao){
83        this.componentDao = dao;
84     }
85     /** @param dao A Deliverable data access object */
86     public void setDeliverableDao(DeliverableDao dao){
87        this.deliverableDao = dao;
88     }
89     /** @param dao A Component type data access object */
90     public void setComponentTypeDao(ComponentTypeDao dao){
91        this.componentTypeDao = dao;
92     }
93     /** @param dao A Deliverable type data access object */
94     public void setDeliverableTypeDao(DeliverableTypeDao dao){
95        this.deliverableTypeDao = dao;
96     }
97     /** @param manager A Event publication manager implementation instance */
98     public void setEventPublicationManager(EventPublicationManager manager){
99        this.publicationManager = manager;
100    }
101 
102 
103    // Implementation of ArtifactManager -------------------------------------
104   
105    /**
106     * Bind a component to an existing assembly. If component is not already
107     * registered, create it. And update its reference assembly (the one that
108     * first contains the component)
109     * @param component The component to bind to assembly
110     * @param assembly The assembly that is containing component
111     */
112    public void bindComponent(Component component, Assembly assembly){
113       if (log.isDebugEnabled())
114          log.debug("Binding component '" + component.getKey() + "' to assembly " + assembly.getKey());
115       // If it's a new component, set its origin assembly.
116       Component other = componentDao.getComponent(component.getKey());
117       if (component.isTransient() && other == null){
118          log.info("Creating a new component '" + component.getKey() + "' from assembly " + assembly.getKey());
119          component.setAssembly(assembly);
120       }
121       // In any case, add this assembly to component.
122       assembly.addComponent(component);
123       // Create or update component.
124       componentDao.save(component);
125    }
126 
127    /**
128     * Get a component having this specified key.
129     * @param key Unique business identifier of component to retrieve
130     * @return The component having this business key
131     */
132    public Component getComponent(String key){
133       // Delegate to dao.
134       return componentDao.getComponent(key);
135    }
136 
137    /**
138     * Retrieve a list of components corresponding to the specified type and created into release
139     * @param type The component type of the components to retrieve
140     * @param release The release the components have been bound to
141     * @return A list of {@code org.figure8.join.businessobjects.artifact.Component}s
142     */
143    public List getComponents(ComponentType type, Release release){
144       // Delegate to dao.
145       return componentDao.getComponentsByRelease(type, release);
146    }
147 
148    /**
149     * Retrieve a list of components of the specified type and contained into release
150     * @param type The component type of the components to retrieve
151     * @param release The release the components have been bound to
152     * @return A list of {@code org.figure8.join.businessobjects.artifact.Component}s
153     */
154    public List getContainedComponents(ComponentType type, Release release){
155       // Delegate to dao.
156       return componentDao.getComponentsInRelease(type, release);
157    }
158 
159    /**
160     * Save a component type within datastore
161     * @param type Type to save (create or update)
162     * @throws DuplicateEntityException if another type with same key already exists
163     */
164    public void saveComponentType(ComponentType type) throws DuplicateEntityException{
165       if (log.isInfoEnabled())
166          log.info("Saving ComponentType with key '" + type.getKey() + "'");
167       // If new type, look if another one with same key exists.
168       if (type.isTransient()){
169          ComponentType other = componentTypeDao.getComponentType(type.getKey());
170          if (other != null){
171             log.error("A ComponentType with same key already exists: " + other.getLabel());
172             throw new DuplicateEntityException("A ComponentType with same key already exists", other);
173          }
174       }
175       // Call save() on dao.
176       componentTypeDao.save(type);
177    }
178 
179    /**
180     * Get a component category having the specified key.
181     * @param key Unique business identifier of the component type to retrieve
182     * @return ComponentType having this <b>key</b>
183     */
184    public ComponentType getComponentType(String key){
185       return componentTypeDao.getComponentType(key);
186    }
187 
188    /**
189     * Retrieve the component types (or category) of software.
190     * @return List of available {@code org.figure8.join.businessobjects.artifact.ComponentType}
191     */
192    public List getComponentTypes(){
193       // Call findAll() on dao.
194       List result = componentTypeDao.findAllSorted("label");
195       if (log.isDebugEnabled())
196          log.debug("Found " + result.size() + " component types for project");
197       return result;
198    }
199 
200    /**
201     * Create a deliverable within datastore and register its content. The
202     * stream parameter may be null if deliverable content should be retrievied
203     * through a SCM extraction or some other mean ...
204     * @param deliverable The new deliverable to register within Join application
205     * @param content The stream containing deliverable content (if any)
206     * @throws InvalidParameterException if deliverable is already registered
207     * @throws DuplicateEntityException if another deliverable with same key already exists
208     */
209    public void registerDeliverable(Deliverable deliverable, InputStream content)
210            throws InvalidParameterException, DuplicateEntityException{
211       log.info("Registering a new deliverable with key '" + deliverable.getKey() + "'");
212 
213       // First ensure that it is not an update.
214       if (!deliverable.isTransient()){
215          log.error("The Deliverable with key '" + deliverable.getKey() + "' has already been registered");
216          throw new InvalidParameterException("The Deliverable '" + deliverable.getKey() + "' is already registered");
217       }
218       // Now check that there's no other deliverable with this key.
219       Deliverable other = deliverableDao.getDeliverable(deliverable.getKey());
220       if (other != null){
221          log.error("A Deliverable with same key already exists: " + other.getKey());
222          throw new DuplicateEntityException("A Deliverable with same key already exists", other);
223       }
224       // Extract deliverable content from SCM if necessary.
225       File directory = null;
226       if (deliverable.getDeliverableType().getVcsDeliverable()){
227          try {directory = extractDeliverableFromVcs(deliverable);}
228          catch (VCSAccessException vcse){
229             // Log and wrap into a runtime exception.
230             log.error("Exception while trying to checkout '" + deliverable.getKey() + "' from SCM");
231             log.error("Here's the detailed message: " + vcse.getMessage());
232             throw new InfrastructureException("Exception while trying to extract '"
233                     + deliverable.getKey() + "' from SCM", vcse);
234          }
235       }
236       // Store deliverable content into repository.
237       try{
238          if (content != null) deliverablesRepository.storeArtifact(deliverable, content);
239          else if (directory != null) deliverablesRepository.storeArtifact(deliverable, directory);
240       }
241       catch (RepositoryException re){
242          // Log and wrap into a runtime exception.
243          log.error("Exception while trying to store '" + deliverable.getKey() + "' into Repository");
244          log.error("Here's the detailed message: " + re.getMessage());
245          throw new InfrastructureException("Exception while trying to store '"
246             + deliverable.getKey() + "' into Repository", re);
247       }
248       // Call save on dao and publish an event.
249       deliverableDao.save(deliverable);
250       publicationManager.publishDeliveryEvent(deliverable);
251    }
252 
253    /**
254     * Save a deliverable within datastore. This method should be used only for
255     * updating existing deliverables. They must have been first created using the
256     * <code>registerDeliverable()</code> method.
257     * @param deliverable The deliverable to save (just an update)
258     * @throws InvalidParameterException if deliverable has not been registered before
259     */
260    public void saveDeliverable(Deliverable deliverable) throws InvalidParameterException{
261       log.info("Saving the deliverable with key '" + deliverable.getKey() + "'");
262 
263       // First, ensure of registration.
264       if (deliverable.isTransient()){
265          log.error("The Deliverable with key '" + deliverable.getKey() + "' has not been registered before");
266          throw new InvalidParameterException("The Deliverable should be registered before saved !");
267       }
268       // Call save on dao.
269       deliverableDao.save(deliverable);
270    }
271 
272    /**
273     * Get a deliverable having this specified key.
274     * @param key Unique business identifier of deliverable to retrieve
275     * @return The deliverable having this business key
276     */
277    public Deliverable getDeliverable(String key){
278       return deliverableDao.getDeliverable(key);
279    }
280 
281    /**
282     * Retrieve a list of deliverables corresponding to the specified type
283     * @param type The deliverable type of the deliverables to retrieve
284     * @param maxResult An int to limit the size of list returned
285     * @return A list of {@code org.figure8.join.businessobjects.artifact.Deliverable}s
286     */
287    public List getLastDeliverables(DeliverableType type, int maxResult){
288       // Delegate to dao.
289       List result = deliverableDao.getLastDeliverables(type, maxResult);
290       if (log.isDebugEnabled())
291          log.debug("Found " + result.size() + " last deliberables of type " + type.getLabel());
292       return result;
293    }
294 
295    /**
296     * Retrieve a list of deliverables corresponding to the specified type for this release
297     * @param type The deliverable type of the deliverables to retrieve
298     * @param release The release the deliverables have been bound to
299     * @return A list of {@code org.figure8.join.businessobjects.artifact.Deliverable}s
300     */
301    public List getDeliverables(DeliverableType type, Release release){
302       // Delegate to dao.
303       List result = deliverableDao.getDeliverablesByRelease(type, release);
304       if (log.isDebugEnabled())
305          log.debug("Found " + result.size() + " deliberables of type "
306                  + type.getLabel() + " for release '" + release.getName() + "'");
307       return result;
308    }
309 
310    /**
311     * Set the repository to use for storing deliverables. This repository
312     * is necessary when registering a new Deliverables.
313     * @param repository The repository for storing deliverables content
314     */
315    public void setDeliverablesRepository(Repository repository){
316       this.deliverablesRepository = repository;
317    }
318 
319    /**
320     * Save a deliverable type within datastore. If type is a newly created type,
321     * its key should a non existing one. Otherwise, a DuplicateEntityException will
322     * thrown. If type is already existing, the key is an immutable field an a runtime
323     * exception exception will be thrown if it has changed.
324     * @param type Type to save (create or update)
325     * @throws DuplicateEntityException if another type with same key already exists
326     */
327    public void saveDeliverableType(DeliverableType type) throws DuplicateEntityException{
328       if (log.isInfoEnabled())
329          log.info("Saving DeliverableType with key '" + type.getKey() + "'");
330       // If new type, look if another one with same key exists.
331       if (type.isTransient()){
332          DeliverableType other = getDeliverableType(type.getKey());
333          if (other != null){
334             log.error("A DeliverableType with same key already exists: " + other.getLabel());
335             throw new DuplicateEntityException("A DeliverableType with same key already exists", other);
336          }
337       }
338       // Call save() on dao.
339       deliverableTypeDao.save(type);
340    }
341 
342    /**
343     * Get a deliverable category having the specified key.
344     * @param key Unique business identifier of the deliverable type to retrieve
345     * @return DeliverableType having this <b>key</b>
346     */
347    public DeliverableType getDeliverableType(String key){
348       return deliverableTypeDao.getDeliverableType(key);
349    }
350 
351    /**
352     * Retrieve the deliverable types (or category) of software.
353     * @return List of available {@code org.figure8.join.businessobjects.artifact.DeliverableType}
354     */
355    public List getDeliverableTypes(){
356       // Call findAll() on dao.
357       List result = deliverableTypeDao.findAll();
358       if (log.isDebugEnabled())
359          log.debug("Found " + result.size() + " deliberable types for project");
360       return result;
361    }
362 
363 
364    // Private ------------------------------------------------------------------
365 
366    /**
367     * Extract deliverable coming from SCM into a local directory
368     * @param deliverable The description of deliverable to checkout
369     * @throws InvalidParameterException if VCSAccessor cannot be initialized
370     * @throws VCSAccessException if checkout cannot be done
371     * @return The File representing directory where checkout was done
372     */
373    private File extractDeliverableFromVcs(Deliverable deliverable) throws InvalidParameterException, VCSAccessException{
374       // Extract into a temporary file.
375       String tmp = System.getProperty("java.io.tmpdir");
376       File tmpDir = new File(tmp, deliverable.getKey());
377       tmpDir.mkdir();
378       tmpDir.deleteOnExit();
379       // Now, retrieve accessor to checkout.
380       VCSAccessor accessor = deliverable.getDeliverableType().getVCSAccessor();
381       if (log.isInfoEnabled()){
382          log.info("Temporary directory created for checking out '" + deliverable.getKey() + "': " + tmpDir.getPath());
383          log.info("Trying to checkout from SCM " + accessor.getRootRepository() + "...");
384       }
385       // Do the login -> checkout -> logout command.
386       accessor.login();
387       accessor.checkout(deliverable.getVersionInfo(), tmpDir.getPath());
388       accessor.logout();
389 
390       return tmpDir;
391    }
392 }