Source code: com/flexstor/flexdbserver/services/asset/MoveAndChownService.java
1 /*
2 * MoveAndChownService.java
3 *
4 * Copyright $Date: 2003/08/11 02:22:28 $ FLEXSTOR.net Inc.
5 *
6 * This work is licensed for use and distribution under license terms found at
7 * http://www.flexstor.org/license.html
8 *
9 */
10
11 package com.flexstor.flexdbserver.services.asset;
12
13 import java.io.IOException;
14 import java.util.Vector;
15
16 import com.flexstor.common.constants.AssetRolesI;
17 import com.flexstor.common.data.ActionData;
18 import com.flexstor.common.data.ActionResult;
19 import com.flexstor.common.data.ejb.disguiserecord.AssetRoleData;
20 import com.flexstor.common.data.ejb.disguiserecord.DisguiseAssetRecordData;
21 import com.flexstor.common.data.ejb.disguiserecord.DisguiseRecordData;
22 import com.flexstor.common.errorlogger.FlexError;
23 import com.flexstor.common.importprocessor.ImportCtlData;
24 import com.flexstor.common.importprocessor.ImportData;
25 import com.flexstor.common.importprocessor.ImportResult;
26 import com.flexstor.common.io.xfile.FlexXFile;
27 import com.flexstor.common.io.xfile.XFileMove;
28 import com.flexstor.common.resources.Resources;
29 import com.flexstor.common.services.ServiceArgumentsI;
30 import com.flexstor.common.settings.Settings;
31 import com.flexstor.common.util.ServerList;
32 import com.flexstor.flexdbserver.services.Service;
33 import com.flexstor.flexdbserver.services.ServiceContext;
34 import com.flexstor.flexdbserver.util.PathAnalyzer;
35 import com.flexstor.flexdbserver.util.PathBuilder;
36
37 /**
38 * <P>
39 * MoveAndChownService <BR>
40 * <BLOCKQUOTE>
41 * This service provides the functionality to move a file and then change the ownership
42 * of that file. <BR>
43 * Note: The majority of the code was copied from the ImportMoveService. Only
44 * the changeTheOwner method is new.
45 * </BLOCKQUOTE>
46 * </P>
47 *
48 * <P>
49 * Configurable Properties in services.config <BR>
50 * <BLOCKQUOTE>
51 * None
52 * </BLOCKQUOTE>
53 * </P>
54 *
55 * Configurable Properties in roletype_services.config <BR>
56 *
57 * <!-- THE ACTUAL TABLE: -->
58 *
59 * <TABLE BORDER="1" CELLPADDING="3" CELLSPACING="3">
60 * <CAPTION ALIGN=TOP>
61 * <B> In/Out Properties for Assets </B>
62 * </CAPTION>
63 * <TR>
64 * <FONT SIZE=+1><B>
65 * <TH WIDTH="120">Attribute</TH>
66 * <TH WIDTH="30">IN</TH> <TH WIDTH="30">OUT</TH> <TH WIDTH="30">Default IN</TH> <TH WIDTH="30">Default OUT</TH>
67 * </B></FONT>
68 * </TR>
69 * <TR>
70 * <TH ALIGN=LEFT><FONT SIZE=+1><B>ROLE</B></FONT></TH><TD ALIGN=CENTER>   </TD> <TD ALIGN=CENTER>   </TD> <TD ALIGN=CENTER> ALL </TD> <TD ALIGN=CENTER> ALL </TD>
71 * </TR>
72 * <TR><TH> Highres </TH> <TD ALIGN=CENTER> X </TD> <TD ALIGN=CENTER> X </TD> <TD ALIGN=CENTER>   </TD> <TD ALIGN=CENTER>   </TD></TR>
73 * <TR><TH> Lowres </TH> <TD ALIGN=CENTER> X </TD> <TD ALIGN=CENTER> X </TD> <TD ALIGN=CENTER>   </TD> <TD ALIGN=CENTER>   </TD></TR>
74 * <TR><TH> Thumbnail </TH> <TD ALIGN=CENTER> X </TD> <TD ALIGN=CENTER> X </TD> <TD ALIGN=CENTER>   </TD> <TD ALIGN=CENTER>   </TD></TR>
75 * <TR><TH> Layout </TH> <TD ALIGN=CENTER> X </TD> <TD ALIGN=CENTER> X </TD> <TD ALIGN=CENTER>   </TD> <TD ALIGN=CENTER>   </TD></TR>
76 * <TR><TH> Video </TH> <TD ALIGN=CENTER> X </TD> <TD ALIGN=CENTER> X </TD> <TD ALIGN=CENTER>   </TD> <TD ALIGN=CENTER>   </TD></TR>
77 * <TR><TH> Audio </TH> <TD ALIGN=CENTER> X </TD> <TD ALIGN=CENTER> X </TD> <TD ALIGN=CENTER>   </TD> <TD ALIGN=CENTER>   </TD></TR>
78 * <TR>
79 * <TH ALIGN=LEFT><FONT SIZE=+1><B>TYPE</B></FONT></TH>
80 * <TD ALIGN=CENTER> X </TD> <TD ALIGN=CENTER> X </TD> <TD ALIGN=CENTER> ALL </TD> <TD ALIGN=CENTER> ALL </TD></TR>
81 * </TR>
82 * <TR>
83 * <TH ALIGN=LEFT><FONT SIZE=+1><B>FLAG</B></FONT></TH>
84 * </TR>
85 * <TR><TH> PARENT </TH> <TD ALIGN=CENTER> X </TD> <TD ALIGN=CENTER> X </TD> <TD ALIGN=CENTER> X </TD> <TD ALIGN=CENTER> X </TD></TR>
86 * <TR><TH> CHLDREN </TH> <TD ALIGN=CENTER> X </TD> <TD ALIGN=CENTER> X </TD> <TD ALIGN=CENTER>   </TD> <TD ALIGN=CENTER>   </TD></TR>
87 * <TR><TH> ALL </TH> <TD ALIGN=CENTER> X </TD> <TD ALIGN=CENTER> X </TD> <TD ALIGN=CENTER>   </TD> <TD ALIGN=CENTER>   </TD></TR>
88 * <TR><TH> TEMP_PARENT </TH> <TD ALIGN=CENTER> X </TD> <TD ALIGN=CENTER> X </TD> <TD ALIGN=CENTER>   </TD> <TD ALIGN=CENTER>   </TD></TR>
89 * <TR><TH> TEMP_CHILDREN </TH> <TD ALIGN=CENTER> X </TD> <TD ALIGN=CENTER> X </TD> <TD ALIGN=CENTER>   </TD> <TD ALIGN=CENTER>   </TD></TR>
90 * <TR><TH> TEMP_ALL </TH> <TD ALIGN=CENTER> X </TD> <TD ALIGN=CENTER> X </TD> <TD ALIGN=CENTER>   </TD> <TD ALIGN=CENTER>   </TD></TR>
91 * </TABLE>
92 *
93 * <P>
94 * Input Data Object <BR>
95 * <BLOCKQUOTE>
96 * com.flexstor.common.importprocessor.ImportData
97 * </BLOCKQUOTE>
98 * </P>
99 *
100 * <P>
101 * Output Data Object <BR>
102 * <BLOCKQUOTE>
103 * com.flexstor.common.importprocessor.ImportResult
104 * </BLOCKQUOTE>
105 * </P>
106 */
107 public class MoveAndChownService
108 implements Service
109 {
110 public static final String IDENTIFIER = "$Id: MoveAndChownService.java,v 1.4 2003/08/11 02:22:28 aleric Exp $";
111
112 protected ServiceContext context;
113 protected int id = -1;
114 protected String fileSeparator;
115 protected ImportData refImportData = null;
116 protected ImportCtlData refCtlData = null;
117 private String sThisService = "MoveAndChownService";
118 private String sServer = null;
119 private boolean bFromPreservice = false;
120
121 /**
122 * Calls before the service is initialized (before initData is called) to
123 * pass information about the environment in which the service is running.
124 * This environment consists of information about the properties set for the
125 * service in one of these files (services.config, roletype_services.config,
126 * or *.ctl), plus methods to access other information such as an instance
127 * of the service broker to invoke other services, the transaction id for
128 * the service, file separator character and local path for the installation
129 * directory and configuration directory.
130 *
131 * @param context Holds information about the environment in which the service
132 * is running.
133 */
134 public void setServiceContext( ServiceContext context )
135 {
136 this.context = context;
137 id = context.getTransactionId();
138 fileSeparator = context.getFileSeparator();
139 }
140
141 /**
142 * A data initialization method called at the beginning of the service.
143 * The input argument, ActionData must be cast into its subclass, ImportData
144 * in order to extract the CopyService specific data from it.
145 */
146 public void initData(ActionData actionData)
147 {
148 //5526=Import Copy Service
149 sThisService = Resources.get(5526) + " (" + id + ")";
150
151 refImportData = (ImportData) actionData;
152
153 // Get the ctl data object
154 refCtlData = refImportData.getCtlDataRef();
155 // Get the FlexDBServer host
156 sServer = Settings.getString( Settings.APP_SERVER_HOST );
157 // Determine if this service was called from a list of preservices
158 String sProcess = context.getProperty( ServiceArgumentsI.PROCESS );
159 if ( sProcess.equals( "Import " + AssetServiceManager.PRESERVICES ) )
160 bFromPreservice = true;
161 }
162
163 /**
164 * The start of the Copy Service.
165 */
166 public ActionResult go()
167 {
168 ImportResult result = new ImportResult(true);
169
170 if (refImportData != null)
171 {
172 //get ROLE values
173 String role_in = context.getProperty(ServiceArgumentsI.ROLE_DATA_SOURCE);
174 String role_out = context.getProperty(ServiceArgumentsI.ROLE_DATA_DESTINATION);
175
176 // get the TYPE values
177 String type_in = context.getProperty(ServiceArgumentsI.TYPE_DATA_SOURCE);
178 String type_out = context.getProperty(ServiceArgumentsI.TYPE_DATA_DESTINATION);
179
180 //get FLAG values
181 String flag_in = context.getProperty(ServiceArgumentsI.FLAG_DATA_SOURCE);
182 String flag_out = context.getProperty(ServiceArgumentsI.FLAG_DATA_DESTINATION);
183
184 System.out.println( "arguments: " + role_in + ", " + role_out + ", " + type_in + ", " + type_out + ", " + flag_in + ", " + flag_out );
185
186 //downcast to a ImportData object and get the DisguiseRecord
187 DisguiseRecordData disguiseData = refImportData.getDisguiseRecordRef();
188
189 // get the list of in and out assets and set the full_text_path field
190 Vector vInAssets = disguiseData.getAssets( role_in, type_in, flag_in );
191 Vector vOutAssets = disguiseData.getAssets( role_out, type_out, flag_out );
192
193 if ( vInAssets != null && vInAssets.size() > 0 )
194 {
195 DisguiseAssetRecordData assetIn, assetOut;
196 XFileMove copyRef = new XFileMove();
197 String sFileName, sInputPath, sOutputPath;
198
199 for ( int i = 0; i < vInAssets.size(); i++ )
200 {
201 assetIn = (DisguiseAssetRecordData) vInAssets.elementAt(i);
202 try
203 {
204 assetOut = (DisguiseAssetRecordData) vOutAssets.elementAt(i);
205 }
206 catch ( ArrayIndexOutOfBoundsException aioobe )
207 {
208 System.out.println( "Creating new assetOut" );
209 // If role and type are default, use the ones in the assetIn
210 int nRoleOutId = -1;
211 if ( role_out.equals( ServiceArgumentsI.DEFAULT_ROLE ) )
212 nRoleOutId = assetIn.getAssetRoleId();
213 else
214 nRoleOutId = getRoleId( role_out );
215 if ( type_out.equals( ServiceArgumentsI.DEFAULT_TYPE ) )
216 type_out = assetIn.getAssetFileType();
217
218 assetOut = new DisguiseAssetRecordData();
219 AssetRoleData role = new AssetRoleData();
220 role.setAssetRoleId( nRoleOutId );
221 role.setAssetFileType( type_out );
222 if ( flag_out.equals( "TEMP" ) )
223 role.setTempRole( true );
224 assetOut.setAssetRole( role );
225 assetIn.addChildAsset( assetOut );
226 }
227
228 sFileName = assetIn.getFileName();
229 sInputPath = PathBuilder.constructPath( assetIn.getServer(), assetIn.getLocation(), true );
230 sOutputPath = createOutputPath( sInputPath, assetIn.getAssetRoleId() );
231 if ( sOutputPath != null )
232 {
233 if ( copyRef.move( sInputPath + sFileName, sOutputPath + sFileName ) ) {
234 storeNewLocation( sOutputPath, assetOut, assetIn );
235 changeTheOwner( fileSeparator + assetIn.getLocation() + sFileName);
236 }
237 else
238 disguiseData.deleteAsset( assetIn );
239 }
240 else
241 {
242 // This else could be reached only in the first iteration of the for loop,
243 // after that it will never get here because the base destination was found
244 // in createOutputPath().
245 //6518=Destination directory not specified. Cannot proceed.
246 refImportData.addErrorRecord( new FlexError(FlexError.CRITICAL, sThisService, IDENTIFIER, 6518 ) );
247 result.setSuccess(false);
248 break;
249 }
250 }
251 // If this is a preservice, in ImportCtlData replace the HIGHFILELISTBASE with
252 // the HIGHCOPYBASE so in next services we use it as the base path ( specially for alchemy )
253 if ( bFromPreservice )
254 {
255 refCtlData.removeItem( "HIGHFILELISTBASE", refCtlData.getValuePerKey("HIGHFILELISTBASE") );
256 refCtlData.addValuePerKey( "HIGHFILELISTBASE" , refCtlData.getValuePerKey("HIGHCOPYBASE") );
257 }
258 }
259 else
260 {
261 //6290=Could not find assets of the following role, type and flag: %%1 %%2 %%3
262 refImportData.addErrorRecord( new FlexError(FlexError.CRITICAL, sThisService, IDENTIFIER, 6290, new String[] { role_in, type_in, flag_in } ) );
263 result.setSuccess(false);
264 }
265 }
266 else
267 {
268 //6291=Cannot operate on an empty data object
269 refImportData.addErrorRecord( new FlexError(FlexError.CRITICAL, sThisService, IDENTIFIER, 6291 ) );
270 result.setSuccess(false);
271 }
272 result.setImportData(refImportData);
273 return result;
274 } // go()
275
276 private String createOutputPath( String sInputPath, int nRoleId )
277 {
278 boolean bCopyFlat = true;
279 try
280 {
281 bCopyFlat = (Boolean.valueOf( context.getProperty("copyflat") )).booleanValue();
282 }
283 catch ( NullPointerException npe ) { bCopyFlat = true; }
284
285 // Try to get the destination set in the service properties (configuration files)
286 String sBaseDestination = context.getProperty("destination");
287 if ( sBaseDestination != null && sBaseDestination.equals("") == false )
288 {
289 // Don't add the test for bCopyFlat in the above if statement!!!
290 // If !bCopyFlat it would be wrong to go to the next else if...
291 if ( bCopyFlat )
292 {
293 if ( PathAnalyzer.getRemoteFileProtocol(sBaseDestination) == null )
294 sBaseDestination = PathBuilder.constructPath( sServer, sBaseDestination, true );
295 return sBaseDestination;
296 }
297 }
298 else if ( bFromPreservice ) // If from preservice and not destination set, use the copy base properties
299 {
300 if ( nRoleId == AssetRolesI.LOWRES )
301 sBaseDestination = refCtlData.getValuePerKey("LOWCOPYBASE");
302 else if ( nRoleId == AssetRolesI.HIGHRES )
303 sBaseDestination = refCtlData.getValuePerKey("HIGHCOPYBASE");
304 }
305
306 // Lets check once more if sBaseDestination is null; if it is then exit
307 if ( sBaseDestination != null && sBaseDestination.equals("") == false )
308 {
309 if ( PathAnalyzer.getRemoteFileProtocol(sBaseDestination) == null )
310 sBaseDestination = PathBuilder.constructPath( sServer, sBaseDestination, true );
311 }
312 else
313 return null;
314
315 String sBaseOriginal;
316 if ( nRoleId == AssetRolesI.LOWRES )
317 sBaseOriginal = refCtlData.getValuePerKey("LOWFILELISTBASE");
318 else
319 sBaseOriginal = refCtlData.getValuePerKey("HIGHFILELISTBASE");
320
321 if ( PathAnalyzer.getRemoteFileProtocol(sBaseOriginal) == null )
322 sBaseOriginal = PathBuilder.constructPath( sServer, sBaseOriginal, true );
323
324 System.out.println("BaseDestination is: " + sBaseDestination);
325 System.out.println("Moving flat: " + bCopyFlat );
326 return buildCompositeDir( sInputPath, sBaseDestination, sBaseOriginal );
327 }
328
329 /**
330 * Build up the directory from the element & root paths specified.
331 * @param sLocation The element path.
332 * @param sRootPath The root path.
333 */
334 protected String buildCompositeDir(String sLocation, String sRootPath, String sListBasePath)
335 {
336 String sOutputPath = sRootPath;
337
338 // Find the base path in the user specified input file path
339 if (sLocation.startsWith(sListBasePath))
340 sOutputPath += sLocation.substring( sListBasePath.length() );
341 else
342 sOutputPath += sLocation;
343
344 return sOutputPath;
345 } // buildCompositeDir
346
347 private int getRoleId( String sRole )
348 {
349 // Get the proper Role Id
350 if ( sRole.equalsIgnoreCase("LOWRES") )
351 return AssetRolesI.LOWRES;
352 else if ( sRole.equalsIgnoreCase("THUMBNAIL") )
353 return AssetRolesI.THUMBNAIL;
354 else if ( sRole.equalsIgnoreCase("LAYOUT") )
355 return AssetRolesI.LAYOUT;
356 else if ( sRole.equalsIgnoreCase("AUDIO") )
357 return AssetRolesI.AUDIO;
358 else if ( sRole.equalsIgnoreCase("VIDEO") )
359 return AssetRolesI.VIDEO;
360 else if ( sRole.equalsIgnoreCase("ALL") )
361 return -1;
362 else
363 return AssetRolesI.HIGHRES; // HIGHRES is the default
364 }
365
366 private void storeNewLocation( String sOutputPath, DisguiseAssetRecordData assetOut, DisguiseAssetRecordData assetIn )
367 {
368 // This method will store the new location ( the destination location ) as the new
369 // location of the asset, and if this ImportCopy Service was ran as a preservice,
370 // Then the old location will be set in the copy_source values for later update of
371 // the ASSETS_COPY_SOURCE in the DBUpdate Service.
372 if ( bFromPreservice )
373 {
374 System.out.println( "Setting copy source values..." );
375 assetOut.setCopySource( true );
376 assetOut.setCopySourceServer( assetOut.getServer() );
377 assetOut.setCopySourceLocation( assetOut.getLocation() );
378 assetOut.setCopySourceFileName( assetOut.getFileName() );
379 }
380
381 if ( sOutputPath.startsWith( "nfs" ) )
382 {
383 FlexXFile xOutputPath = new FlexXFile( sOutputPath );
384 assetOut.setServer( ServerList.getServerName( xOutputPath.getServer() ) );
385 assetOut.setLocation( xOutputPath.getLocalPath() + fileSeparator );
386 assetOut.setFileName( assetIn.getFileName() );
387 }
388 else
389 {
390 assetOut.setServer( assetIn.getServer() );
391 assetOut.setLocation( sOutputPath );
392 assetOut.setFileName( assetIn.getFileName() );
393 }
394 }
395
396 private void changeTheOwner( String sFullPathToFile )
397 {
398 Process pr = null;
399 String sCommand[] = new String[3];
400 String sUserID = context.getProperty("userid");
401
402 if (sUserID == null) {
403 System.out.println("userid was left blank, can't chown");
404 } else {
405 System.out.println("BGP: will chown "+ sUserID +" "+ sFullPathToFile);
406 sCommand[0] = "/bin/chown";
407 sCommand[1] = sUserID;
408 sCommand[2] = sFullPathToFile;
409 try {
410 pr = Runtime.getRuntime().exec(sCommand);
411
412 // Wait for process completion
413 pr.waitFor();
414 } catch (IOException e) {
415 System.out.println("IOE Error during chown...");
416 } catch (InterruptedException e) {
417 System.out.println("IE Error during chown...");
418 } finally {
419 if ( pr != null ) {
420 pr.destroy();
421 pr = null;
422 }
423 }
424 }
425 }
426 }
427