1 /**
2 * Copyright 2005-2006 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.scripting.ant.tasks;
16
17 import org.figure8.join.services.remoting.ArtifactService;
18 import org.figure8.join.services.remoting.InvalidSessionException;
19 import org.figure8.join.services.remoting.beans.RemoteComponent;
20 import org.figure8.join.services.security.InvalidLoginException;
21
22 import org.apache.tools.ant.Project;
23 import org.apache.tools.ant.BuildException;
24 import org.apache.tools.ant.DirectoryScanner;
25 import org.apache.tools.ant.types.FileSet;
26
27 import java.io.File;
28 import java.util.ArrayList;
29 import java.rmi.RemoteException;
30 /**
31 * This an Ant task to use for binding a component being built/discovered to a
32 * specified assembly and/or build. <br/>
33 * As an example, use a <i>bindcomponent</i> that way to ensure attaching a
34 * component to an assembly : <br/>
35 * <code>
36 * >bindcomponent type="myComponent" assembly="myassembly-r1.0-v01"
37 * version="001" url="http://mydomain.org:8080/join"<<br/>
38 * >fileset dir="${src.dir}/myComponent" includes="*.*"/<
39 * >/bindcomponent<
40 * </code><br/>
41 * That task will then connect to Join system denoted by url to see if component of
42 * type "myComponent" exists with version "001". If no, il will create it into Join
43 * system, specifying its size using files from nested filesets. Finally, it will
44 * attach existing or newly created component to the existing "myassembly-r1.0-v01"
45 * assembly.
46 * <br/>
47 * This task is very useful when creating an assembly using an Ant script and
48 * introspecting its content, searching for contained components : it allows you
49 * to trace what you have dynamically discovered.
50 * <br/>
51 * When component version is not easily extractable, you can replace <i>version</i>
52 * attribute by <i>extractor</i> and thus specifying a {@see VersionInfoExtractor}
53 * implementation to use for extracting version info from files in nested filesets.
54 * <br/>
55 * @author <a href="mailto:laurent.broudoux@free.fr">Laurent Broudoux</a>
56 * @version $Revision: 1.1 $
57 */
58 public class BindComponentTask extends RemoteServiceTask{
59
60
61
62 /** The component type to bind a component for */
63 private String type;
64 /** The assembly that contains component */
65 private String assembly;
66 /** The component version information */
67 private String version;
68 /** The component version extractor implementation to use */
69 private Class extractor;
70 /** A list of Ant filesets to process */
71 private ArrayList fileSets = new ArrayList();
72
73 /** The version information extractor instance used for retrieving component version */
74 protected VersionInfoExtractor versionExtractor = null;
75
76
77
78
79 /** Creates a new instance of BindComponentTask */
80 public BindComponentTask(){
81 }
82
83
84
85
86 /** @return The component type to bind a component for */
87 public String getType(){
88 return type;
89 }
90 /** @param type The component type to bind a component for */
91 public void setType(String type){
92 this.type = type;
93 }
94 /** @return The assembly that contains component */
95 public String getAssembly(){
96 return assembly;
97 }
98 /** @param assembly The assembly that contains component */
99 public void setAssembly(String assembly){
100 this.assembly = assembly;
101 }
102 /** @return The component version information */
103 public String getVersion(){
104 return version;
105 }
106 /** @param version The component version information */
107 public void setVersion(String version){
108 this.version = version;
109 }
110 /** @return The component version extractor implementation to use */
111 public Class getExtractor(){
112 return extractor;
113 }
114 /** @param extractor The component version extractor implementation to use */
115 public void setExtractor(Class extractor){
116 this.extractor = extractor;
117 }
118
119 /**
120 * Adds a set of files (nested fileset element)
121 * @param set A FileSet containing files to process
122 */
123 public void addFileset(FileSet set){
124 fileSets.add(set);
125 }
126
127
128
129
130 /**
131 * Execute this task : do the binding of configured component
132 * @throws BuildException if something wrong occurs during task process
133 */
134 public void execute() throws BuildException{
135
136 validateAttributes();
137
138 File[] files = getFilesFromFileSets();
139
140
141 if (version == null || version.length() == 0){
142 try {version = versionExtractor.extractVersionInfo(files);}
143 catch (Exception e){
144 log("Exception while extracting version: " + e.getMessage(), Project.MSG_ERR);
145 throw new BuildException("Problem during version extraction: " + e.getMessage(), getLocation());
146 }
147 }
148
149 bindComponent(version, files);
150 }
151
152
153
154
155 /**
156 * Validate this task attributes before execution.
157 * @throws BuildException if a mandatory attribute is not present
158 */
159 protected void validateAttributes() throws BuildException{
160
161 if (type == null || type.length() == 0)
162 throw new BuildException("No component type specified for bindComponent", getLocation());
163
164 if (assembly == null || assembly.length() == 0)
165 throw new BuildException("No assembly specified for bindComponent", getLocation());
166
167 if (version == null && extractor == null)
168 throw new BuildException("No version information nor extractor implementation specified for bindComponent",
169 getLocation());
170
171 if (fileSets.isEmpty())
172 throw new BuildException("No FileSet specified for bindComponent", getLocation());
173
174
175 if (extractor != null){
176 try {versionExtractor = (VersionInfoExtractor)extractor.newInstance();}
177 catch (Exception e){
178 log("Exception while creating VersionInfoExtractor impl: " + e.getMessage(), Project.MSG_ERR);
179 throw new BuildException("Extractor must be an implementation of VersionInfoExtractor", getLocation());
180 }
181 }
182 }
183
184 /**
185 * Build an array of included files.
186 * @return An array of files build from fileSets
187 */
188 protected File[] getFilesFromFileSets(){
189
190 ArrayList fileList = new ArrayList();
191 for (int i=0; i < fileSets.size(); i++){
192
193 FileSet fs = (FileSet)fileSets.get(i);
194 DirectoryScanner ds = fs.getDirectoryScanner(getProject());
195 File fromdir = fs.getDir(getProject());
196 String[] srcfiles = ds.getIncludedFiles();
197 for (int j=0; j < srcfiles.length; j++)
198 fileList.add(new File(fromdir, srcfiles[j]));
199 }
200
201
202 File[] files = new File[fileList.size()];
203 files = (File[])fileList.toArray(files);
204 return files;
205 }
206
207 /**
208 * Do the real component binding (remote service invocation)
209 * @param files The files representing component
210 * @throws BuildException if service invocation fails
211 */
212 protected void bindComponent(String version, File[] files) throws BuildException{
213
214 ArtifactService service = (ArtifactService)retrieveRemoteService("ArtifactService", ArtifactService.class);
215
216 String token = null;
217 try{
218
219 token = loginToRemoteService(service);
220 long size = computeSizeInBytes(files);
221 log("Bind the '" + type + "' component " + version + " using remote service", Project.MSG_DEBUG);
222 RemoteComponent component = new RemoteComponent(version, size, type);
223 service.bindComponent(token, component, assembly);
224 }
225 catch (InvalidLoginException ile){
226
227 log("InvalidLoginException while logging to remote service: " + ile.getMessage(), Project.MSG_ERR);
228 throw new BuildException("Exception while logging to remote service", ile, getLocation());
229 }
230 catch (InvalidSessionException ise){
231
232 log("InvalidSessionException while invoking remote service: " + ise.getMessage(), Project.MSG_ERR);
233 throw new BuildException("Exception while invoking remote service", ise, getLocation());
234 }
235 catch (RemoteException re){
236
237 log("RemoteException while logging to remote service: " + re.getMessage(), Project.MSG_ERR);
238 throw new BuildException("Exception while logging to remote service", re, getLocation());
239 }
240 catch (Exception e){
241
242 log("Unexpected exception while binding component: " + e.getMessage(), Project.MSG_ERR);
243 throw new BuildException("Unexpected exception while binding component", e, getLocation());
244 }
245
246 releaseRemoteService(service, token);
247 }
248
249 /**
250 * Compute the sum of files weigth. This sum is expressed in bytes.
251 * @param files The set of files to sum weigth.
252 */
253 protected long computeSizeInBytes(File[] files) throws Exception{
254 long sum = 0;
255 for (int i=0; i<files.length ; i++)
256 sum += files[i].length();
257 return sum;
258 }
259 }
260