View Javadoc

1   /**
2    * Copyright 2005-2008 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.services.remoting.xmlrpc;
16  
17  import org.figure8.join.core.DuplicateEntityException;
18  import org.figure8.join.core.InvalidParameterException;
19  import org.figure8.join.services.remoting.ArtifactService;
20  import org.figure8.join.services.remoting.ResourceService;
21  import org.figure8.join.services.remoting.ProcessControlService;
22  import org.figure8.join.services.remoting.InvalidSessionException;
23  import org.figure8.join.services.remoting.beans.RemoteRelease;
24  import org.figure8.join.services.remoting.beans.RemoteComponent;
25  import org.figure8.join.services.remoting.beans.RemoteDeliverable;
26  import org.figure8.join.services.remoting.beans.RemoteDeliverableType;
27  import org.figure8.join.services.remoting.beans.RemoteResourceVersion;
28  import org.figure8.join.services.security.InvalidLoginException;
29  import org.figure8.join.util.LogUtil;
30  
31  import org.apache.commons.logging.Log;
32  import org.apache.commons.beanutils.BeanUtils;
33  
34  import java.io.File;
35  import java.io.FileOutputStream;
36  import java.io.IOException;
37  import java.rmi.RemoteException;
38  import java.util.List;
39  import java.util.Vector;
40  import java.util.Hashtable;
41  /**
42   * This is the default implementation of {@see XmlRcpHandler}
43   * @author <a href="mailto:laurent.broudoux@free.fr">Laurent Broudoux</a>
44   * @version $Revision: 1.3 $
45   */
46  public class DefaultXmlRpcHandler implements XmlRpcHandler{
47  
48  // Static -------------------------------------------------------------------
49  
50     /** Get a commons logger. */
51     private static final Log log = LogUtil.getLog(DefaultXmlRpcHandler.class);
52  
53  
54     // Attributes ---------------------------------------------------------------
55  
56     /** The ArtifactService implementation to dispatch requests to */
57     private ArtifactService artifactService = null;
58     /** The ResourceService implementation to dispatch requests to */
59     private ResourceService resourceService = null;
60     /** The ProcessControlService implementation to dispatch requests to */
61     private ProcessControlService controlService = null;
62  
63  
64     // Constructors -------------------------------------------------------------
65  
66     /** Creates a new instance of DefaultXmlRpcHandler */
67     public DefaultXmlRpcHandler(){
68     }
69  
70  
71     // Public -------------------------------------------------------------------
72  
73     /** @param service The ArtifactService implementation to use */
74     public void setArtifactService(ArtifactService service){
75        this.artifactService = service;
76     }
77     /** @param service The ResourceService implementation to use */
78     public void setResourceService(ResourceService service){
79        this.resourceService = service;
80     }
81     /** @param service The ProcessControlService implementation to use */
82     public void setProcessControlService(ProcessControlService service){
83        this.controlService = service;
84     }
85  
86  
87     // Implementation of XmlRpcHandler ------------------------------------------
88  
89     /**
90      * Authenticates a remote user onto Join application. In case of successfull
91      * authentication, this method returns a token that should be used later as
92      * a parameter for calling services required authorization.
93      * @param username Login of user for authentication
94      * @param password Password of corresponding user
95      * @return An authentication token to reuse later during service call
96      * @throws InvalidLoginException if user cannot be logged
97      * @throws RemoteException if an exception occurs during the remote conversation
98      */
99     public String login(String username, String password) throws InvalidLoginException, RemoteException{
100       return controlService.login(username, password);
101    }
102 
103    /**
104     * Logs out from Join application the user corresponding to the supplied token.
105     * @param token An authentication token obtained with <code>login()</code> method.
106     * @throws RemoteException if an exception occurs during the remote conversation
107     * @return Wether this operation is successfull
108     */
109    public boolean logout(String token) throws RemoteException{
110       controlService.logout(token);
111       return true;
112    }
113 
114    /**
115     * Retrieve all the releases managed within the project.
116     * @param token Authentication token provided earlier by login() method
117     * @return An array representing RemoteRelease objects
118     * @throws InvalidSessionException if user has no valid session on server-side
119     * @throws RemoteException if an exception occurs during the remote conversation
120     */
121    public List getReleases(String token) throws InvalidSessionException, RemoteException{
122       return makeList(artifactService.getReleases(token));
123    }
124 
125    /**
126     * Retrieve all the deliverable categories (or types) managed within the project.
127     * @param token Authentication token provided earlier by login() method
128     * @return An array representing RemoteDeliverableType objects
129     * @throws InvalidSessionException if user has no valid session on server-side
130     * @throws RemoteException if an exception occurs during the remote conversation
131     */
132    public List getDeliverableTypes(String token) throws InvalidSessionException, RemoteException{
133       return makeList(artifactService.getDeliverableTypes(token));
134    }
135 
136    /**
137     * Get the deliverable categories where authenticated user can supply deliverables for.
138     * @param token Authentication token provided earlier by login() method
139     * @return An array representing RemoteDeliverableType objects for deliverables supplying
140     * @throws InvalidSessionException if user has no valid session on server-side
141     * @throws RemoteException if an exception occurs during the remote conversation
142     */
143    public List getDeliverableTypesForDelivery(String token) throws InvalidSessionException, RemoteException{
144       return makeList(artifactService.getDeliverableTypesForDelivery(token));
145    }
146 
147    /**
148     * Supply a new deliverable using the remote wrapper. This wrapper must contains
149     * release and type informations. This delivery may include a File object as deliverable
150     * content if deliverables from this type are not retrieved using direct VCS or SCM connection.
151     * @param token Authentication token provided earlier by login() method
152     * @param releaseName The unique name of Release to supply a deliverable for
153     * @param typeKey The unique key of deliverable type this delivery will be bound to
154     * @param versionInfo The version info (or VCS tag info) for this delivery
155     * @param comments The comments on deliverable creation
156     * @param content The deliverable content if not VCS deliverable
157     * @throws InvalidParameterException if deliverable is already registered or parameter is missing
158     * @throws DuplicateEntityException if another deliverable with same key already exists
159     * @throws InvalidSessionException if user has no valid session on server-side
160     * @throws RemoteException if an exception occurs during the remote conversation
161     * @return Wether this operation is successfull
162     */
163    public boolean supplyDeliverable(String token, String releaseName, String typeKey,
164                                     String versionInfo, String comments, byte[] content)
165            throws InvalidParameterException, DuplicateEntityException, InvalidSessionException, RemoteException{
166 
167       // Retrieve specified RemoteRelease.
168       RemoteRelease release = null;
169       RemoteRelease[] releases = artifactService.getReleases(token);
170       for (int i=0; i<releases.length; i++)
171          if (releases[i].getName().equals(releaseName))
172             release = releases[i];
173       // Retrieve specified RemoteDeliverableType.
174       RemoteDeliverableType type = null;
175       RemoteDeliverableType[] types = artifactService.getDeliverableTypes(token);
176       for (int i=0; i<types.length; i++)
177          if (types[i].getKey().equals(typeKey))
178             type = types[i];
179       // Build a new RemoteDeliverable.
180       RemoteDeliverable deliverable = new RemoteDeliverable(versionInfo, comments, release, type);
181 
182       // Copy content to file if provided.
183       File contentFile = null;
184       if (content != null && content.length > 0){
185          try{
186             contentFile = File.createTempFile("join-xmlrpc", ".tmp");
187             contentFile.deleteOnExit();
188             new FileOutputStream(contentFile).write(content);
189          }
190          catch (IOException ioe){
191             // Log and wrap into RemoteException.
192             log.error("Exception occurs while writing delivery content on temporary file");
193             log.error("Here's the errors message: " + ioe.getMessage());
194             throw new RemoteException("IOException while writinn delivery content to file. Delivery is cancelled.");
195          }
196       }
197       // Delegate request to artifact service.
198       artifactService.supplyDeliverable(token, deliverable, contentFile);
199       return true;
200    }
201 
202    /**
203     * Bind a component to a given assembly.
204     * @param token Authentication token provided earlier by login() method
205     * @param typeKey The unique key of component type this component will be bound to
206     * @param versionInfo The version info for this component
207     * @param size The size in bytes of this component
208     * @param assemblyKey The key of assembly to bind component to
209     * @throws InvalidParameterException if parameter is missing
210     * @throws InvalidSessionException if user has no valid session on server-side
211     * @throws RemoteException if an exception occurs during the remote conversation
212     * @return Wether this operation is successfull
213     */
214    public boolean bindComponent(String token, String typeKey, String versionInfo,
215                                 long size, String assemblyKey)
216            throws InvalidParameterException, InvalidSessionException, RemoteException{
217       // Build intermediate RemoteComponent and delegate to service.
218       RemoteComponent component = new RemoteComponent(versionInfo, size, typeKey);
219       artifactService.bindComponent(token, component, assemblyKey);
220       return true;
221    }
222 
223    /**
224     * Set the specified status to a specified <code>Build</code>.
225     * @param token Authentication token provided earlier by login() method
226     * @param statusKey Unique key idenitifer of the status to set to build
227     * @param buildKey The unique key idenitifer of Build to update status
228     * @throws InvalidSessionException if user has no valid session on server-side
229     * @throws RemoteException if an exception occurs during the remote conversation
230     * @return Wether this operation is successfull
231     */
232    public boolean setBuildStatus(String token, String statusKey, String buildKey)
233            throws InvalidSessionException, RemoteException{
234       controlService.setBuildStatus(token, statusKey, buildKey);
235       return true;
236    }
237 
238    /**
239     * Set the specified status to a specified <code>Assembly</code>.
240     * @param token Authentication token provided earlier by login() method
241     * @param statusKey Unique key idenitifer of the status to set to assembly
242     * @param assemblyKey The unique key idenitifer of Assembly to update status
243     * @throws InvalidSessionException if user has no valid session on server-side
244     * @throws RemoteException if an exception occurs during the remote conversation
245     * @return Wether this operation is successfull
246     */
247    public boolean setAssemblyStatus(String token, String statusKey, String assemblyKey)
248            throws InvalidSessionException, RemoteException{
249       controlService.setAssemblyStatus(token, statusKey, assemblyKey);
250       return true;
251    }
252 
253    /**
254     * Set the specified status to a specified <code>Deployment</code>.
255     * @param token Authentication token provided earlier by login() method
256     * @param statusKey Unique key idenitifer of the status to set to deployment
257     * @param deploymentId The unique identifier of Deployment to retrieve status for
258     * @throws InvalidSessionException if user has no valid session on server-side
259     * @throws NumberFormatException if deploymentId does not represent a long
260     * @throws RemoteException if an exception occurs during the remote conversation
261     * @return Wether this operation is successfull
262     */
263    public boolean setDeploymentStatus(String token, String statusKey, String deploymentId)
264            throws InvalidSessionException, NumberFormatException, RemoteException{
265       // Cast and delegate.
266       long deploymentIdL = Long.valueOf(deploymentId).longValue();
267       controlService.setDeploymentStatus(token, statusKey, deploymentIdL);
268       return true;
269    }
270 
271    /**
272     * Create a new resource version for a specified resource type. This operation
273     * reqires a valid authentication done first and the permissions corresponding
274     * to Joiner security role.
275     * @param token Authentication token provided earlier by login() method
276     * @param versionName The name of the resource version to create
277     * @param versionDescription The description of resource version to create
278     * @param resourceTypeKey The key of resource type this version applies to
279     * @throws InvalidParameterException if parameter is missing
280     * @throws DuplicateEntityException if another version with same name already exists
281     * @throws InvalidSessionException if user has no valid session on server-side
282     * @throws RemoteException if an exception occurs during the remote conversation
283     * @return Wether this operation is successfull
284     */
285    public boolean createResourceVersion(String token, String versionName,
286                                         String versionDescription, String resourceTypeKey)
287            throws InvalidParameterException, DuplicateEntityException, InvalidSessionException, RemoteException{
288       // Build intermediate RemoteResourceVersion and delegate to service.
289       RemoteResourceVersion version = new RemoteResourceVersion(versionName, versionDescription, resourceTypeKey);
290       resourceService.createResourceVersion(token, version);
291       return true;
292    }
293 
294    /**
295     * Update an existing resource with an existing reosurce version. Resource and
296     * version are specified using their names that should be unique within Join system.
297     * This operations requires a valid authentication done first and the persmissions
298     * corresponding to Joiner security role.
299     * @param token Authentication token provided earlier by login() method
300     * @param resourceName The unique name of the resource to update
301     * @param versionName The unique name of the version to update resource with
302     * @throws InvalidParameterException if one of supplied parameters is invalid
303     * @throws InvalidSessionException if user has no valid session on server-side
304     * @throws RemoteException if an exception occurs during the remote conversation
305     * @return Wether this operation is successfull
306     */
307    public boolean updateResource(String token, String resourceName, String versionName)
308            throws InvalidParameterException, InvalidSessionException, RemoteException{
309       resourceService.updateResource(token, resourceName, versionName);
310       return true;
311    }
312 
313 
314    // Private ------------------------------------------------------------------
315 
316    /**
317     * Make a Xml-Rpc array of given beans
318     * @return A list that will be serialized into an {@code &lt;array&gt;}
319     */
320    private List makeList(Object[] beans){
321       // Prepare result.
322       Vector result = new Vector();
323       // Browse beans and make a String or a Struct.
324       for (int i=0; i<beans.length; i++){
325          if (beans[i] instanceof String)
326             result.add(beans[i]);
327          else
328             result.add(makeStructure(beans[i]));
329       }
330       return result;
331    }
332 
333    /**
334     * Make a Xml-Rpc structure of a given bean
335     * @return A Hashtable that will be serialized into a {@code &lt;struct&gt;}
336     */
337    private Hashtable makeStructure(Object bean){
338       try{
339          // Use BeanUtils to describe the bean.
340          return new Hashtable(BeanUtils.describe(bean)){
341             /**
342              * Do not throw NullPointerException if key or value is null.
343              * Do not store the 'class' property of the given bean.
344              */
345             public synchronized Object put(Object key, Object value){
346                if (key == null || value == null || "class".equals(key))
347                   return null;
348                else
349                   return super.put(key, value);
350             }
351          };
352       }
353       catch (Exception e){
354          // Just produce warning before returning null...
355          log.warn("Exception occurs while making structure for bean: " + bean);
356          return null;
357       }
358    }
359 }