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
50
51 /** Get a commons logger... */
52 private static final Log log = LogUtil.getLog(DefaultArtifactManager.class);
53
54
55
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
73
74 /** Creates a new instance of DefaultArtifactManager */
75 public DefaultArtifactManager(){
76 }
77
78
79
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
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
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
122 assembly.addComponent(component);
123
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
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
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
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
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
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
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
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
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
225 File directory = null;
226 if (deliverable.getDeliverableType().getVcsDeliverable()){
227 try {directory = extractDeliverableFromVcs(deliverable);}
228 catch (VCSAccessException vcse){
229
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
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
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
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
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
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
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
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
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
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
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
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
375 String tmp = System.getProperty("java.io.tmpdir");
376 File tmpDir = new File(tmp, deliverable.getKey());
377 tmpDir.mkdir();
378 tmpDir.deleteOnExit();
379
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
386 accessor.login();
387 accessor.checkout(deliverable.getVersionInfo(), tmpDir.getPath());
388 accessor.logout();
389
390 return tmpDir;
391 }
392 }