Source code: com/flexstor/flexdbserver/services/checkincheckout/CheckInServiceManager.java
1 /*
2 * CheckInServiceManager.java
3 *
4 * Copyright $Date: 2003/08/11 02:22:49 $ 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.checkincheckout;
12
13 import java.util.Date;
14 import java.util.Enumeration;
15 import java.util.Iterator;
16 import java.util.Vector;
17
18 import com.flexstor.common.constants.ActionPropertiesI;
19 import com.flexstor.common.constants.AssetRolesI;
20 import com.flexstor.common.constants.RsrcForkConstantsI;
21 import com.flexstor.common.constants.ServicesI;
22 import com.flexstor.common.data.ActionData;
23 import com.flexstor.common.data.ActionResult;
24 import com.flexstor.common.data.AssetRecordData;
25 import com.flexstor.common.errorlogger.FlexError;
26 import com.flexstor.common.gateway.CheckOutCheckInGateway;
27 import com.flexstor.common.gateway.exceptions.TransactionFailedException;
28 import com.flexstor.common.io.xfile.FlexXFile;
29 import com.flexstor.common.io.xfile.XFileCopy;
30 import com.flexstor.common.resources.Resources;
31 import com.flexstor.common.services.SrvcNotAvailException;
32 import com.flexstor.common.settings.Settings;
33 import com.flexstor.common.threadmgr.ThreadCallbackI;
34 import com.flexstor.common.util.Diagnostic;
35 import com.flexstor.common.util.FlexDbServerHost;
36 import com.flexstor.common.util.ServerList;
37 import com.flexstor.flexdbserver.services.ServiceManager;
38 import com.flexstor.flexdbserver.services.lowres.LowresConstants;
39 import com.flexstor.flexdbserver.util.PathAnalyzer;
40 import com.flexstor.flexdbserver.util.PathBuilder;
41
42 /**
43 * CheckInServiceManager provides functionality to control the
44 * sequencial execution of Services during the check-in process
45 */
46 public class CheckInServiceManager
47 extends ServiceManager
48 implements AssetRolesI
49 {
50 // To get the version number from MKS
51 public final static String IDENTIFIER="$Id: CheckInServiceManager.java,v 1.3 2003/08/11 02:22:49 aleric Exp $";
52
53 /** Record States */
54 private static final int NOT_PROCESSED = 0;
55 private static final int ORIGINAL_MOVED = 1;
56 private static final int NEW_VERSION_COPIED = 2;
57 private static final int LOWRES_UPDATED = 3;
58 private static final int DEFAULTVIEW_COPIED = 4;
59 /** Global States */
60 private static final int ASSETS_CHECKED_IN = 5;
61 private static final int ASSETINFO_REGENERATED = 6;
62 private static final int DATABASE_UPDATED = 7;
63 private static final int FILES_ROLLED_BACK = 8;
64 private static final int TEMPDIR_CLEANED = 9;
65
66 protected String sServerName = "";
67 protected ActionData data = null;
68 protected Vector vRecords = null; //records to be processed
69 protected Vector vGoodRecords = null; //records successfully processed
70 protected Vector vBadRecords = null; //records unsuccessfully processed
71 protected Vector vBadStates = null; //state for records unsuccessfully processed
72 protected boolean bContinue = true;
73 protected boolean bInterrupted = false;
74 protected int nGlobalState = NOT_PROCESSED;
75 protected String fileSeparator = "";
76 protected String sTempDir = "";
77 protected CheckOutCheckInGateway checkInGateway = null;
78
79 public CheckInServiceManager( String sIdentifier, ActionData data, ThreadCallbackI caller )
80 {
81 super( data, caller );
82 this.sServerName = sIdentifier;
83 this.data = data;
84
85 // Get the system dependent file separator
86 fileSeparator = java.io.File.separator;
87
88 // Create the temp dir
89 sTempDir = Settings.getString( Settings.APP_SERVER_TMP_DIR );
90 if ( ! sTempDir.endsWith(fileSeparator) )
91 sTempDir += fileSeparator;
92
93 sTempDir += data.getTransId() + fileSeparator;
94 }
95
96 /**
97 * Main loop for sequencial execution of Services.
98 */
99 public ActionResult execute()
100 throws InterruptedException
101 {
102 vGoodRecords = new Vector();
103 vBadRecords = new Vector();
104 vBadStates = new Vector();
105 AssetRecordData record = null;
106 int nRecordState = NOT_PROCESSED;
107 vRecords = (Vector)(data.getRecords()).clone(); // clone, so we leave the original vector intact.
108 try
109 {
110 // Initialize the checkInGateway
111 checkInGateway = new CheckOutCheckInGateway();
112 checkInGateway.connect();
113
114 if ( setStatusToInProgress() )
115 {
116 // Do a shallow copy of the vRecords vector so we can remove elements from it
117 // safely during the for loop
118 Vector vRecordsClone = (Vector) vRecords.clone();
119 try
120 {
121 for ( Enumeration e = vRecordsClone.elements(); e.hasMoreElements(); )
122 {
123 record = (AssetRecordData) e.nextElement();
124 nRecordState = NOT_PROCESSED;
125 bContinue = true;
126
127 if ( !isInterrupted() )
128 moveOriginalToVersionsDir( record );
129
130 if ( bContinue && !isInterrupted() )
131 {
132 nRecordState = ORIGINAL_MOVED;
133 copyNewVersionIntoOriginal( record );
134 }
135
136 if ( bContinue && !isInterrupted() )
137 {
138 nRecordState = NEW_VERSION_COPIED;
139 updateLowres( record );
140 }
141
142 if ( bContinue && !isInterrupted() )
143 {
144 nRecordState = LOWRES_UPDATED;
145 // While copying the default view (thumbnail) around
146 // we should still continue with the check in process
147 // even if the thumbnail process has problems
148 copyDefaultViewToVersionDir( record );
149 }
150
151 if ( bContinue )
152 nRecordState = DEFAULTVIEW_COPIED;
153
154 if ( bContinue && !isInterrupted() )
155 vGoodRecords.addElement( record );
156 else
157 {
158 vBadRecords.addElement( record );
159 vBadStates.addElement( new Integer(nRecordState) );
160 }
161 vRecords.removeElement( record );
162 }
163 }
164 catch ( Exception e )
165 {
166 // If any exception is thrown there, we add the current record to the
167 // list of bad ones so we can safely roll it back
168 if ( record != null )
169 {
170 vBadRecords.addElement( record );
171 vBadStates.addElement( new Integer(nRecordState) );
172 vRecords.removeElement( record );
173 }
174 }
175
176 // If this thread is interrupted, rollback the good records to their original position;
177 // also mark the not-yet-processed record to be rollbacked in the database
178 if ( isInterrupted() )
179 {
180 if ( vGoodRecords.size() > 0 )
181 {
182 for ( int i = 0; i < vGoodRecords.size(); i++ )
183 {
184 vBadRecords.addElement( (AssetRecordData)vGoodRecords.elementAt(i) );
185 vBadStates.addElement( new Integer(DEFAULTVIEW_COPIED) );
186 }
187 vGoodRecords.clear();
188 }
189 if ( vRecords.size() > 0 )
190 {
191 for ( int i = 0; i < vRecords.size(); i++ )
192 {
193 vBadRecords.addElement( (AssetRecordData)vRecords.elementAt(i) );
194 vBadStates.addElement( new Integer(NOT_PROCESSED) );
195 }
196 vRecords.clear();
197 }
198 }
199
200 if ( vGoodRecords.size() > 0 )
201 {
202 // Before regenerating the assets (if required) lets call the bean so we insert
203 // a new row into the roles tables for the new version assets with the information
204 // for the current assets.
205 checkInAssets( vGoodRecords );
206 nGlobalState = ASSETS_CHECKED_IN;
207
208 regenerateAssetsInfo( vGoodRecords );
209 if ( !bContinue )
210 {
211 // If fail, set all records to bad and clear the vRecords vector
212 for ( int i = 0; i < vGoodRecords.size(); i++ )
213 {
214 vBadRecords.addElement( (AssetRecordData) vGoodRecords.elementAt(i) );
215 vBadStates.addElement( new Integer(ASSETS_CHECKED_IN) );
216 }
217 vGoodRecords.removeAllElements();
218 }
219 nGlobalState = ASSETINFO_REGENERATED;
220 }
221 }
222 else // of if ( setStatusToInProgress() )
223 {
224 // If fail, set all records to bad and clear the vRecords vector
225 for ( int i = 0; i < vRecords.size(); i++ )
226 {
227 vBadRecords.addElement( (AssetRecordData) vRecords.elementAt(i) );
228 vBadStates.addElement( new Integer(NOT_PROCESSED) );
229 }
230 }
231
232 updateDatabase( vGoodRecords, vBadRecords );
233 // Next global state means that we already attempt to update the database,
234 // regardless of the status of the update.
235 nGlobalState = DATABASE_UPDATED;
236 }
237 catch ( TransactionFailedException e )
238 {
239 // Set all records in vRecords to bad, if any
240 // Since these records haven't been processed yet, set the state to NOT_PROCESSED
241 for ( int i = 0; i < vRecords.size(); i++ )
242 {
243 vBadRecords.addElement( (AssetRecordData) vRecords.elementAt(i) );
244 vBadStates.addElement( new Integer(NOT_PROCESSED) );
245 }
246 // Set all records in vGoodRecords to bad, if any
247 // Since these records have been fully processed, set the state to DEFAULTVIEW_COPIED
248 // or to ASSETS_CHECKED_IN (in case their version was already created in the database)
249 for ( int i = 0; i < vGoodRecords.size(); i++ )
250 {
251 vBadRecords.addElement( (AssetRecordData) vGoodRecords.elementAt(i) );
252 if ( nGlobalState < ASSETS_CHECKED_IN )
253 vBadStates.addElement( new Integer(DEFAULTVIEW_COPIED) );
254 else
255 vBadStates.addElement( new Integer(ASSETS_CHECKED_IN) );
256 }
257 // 7046=Unable to change database status for this transaction.
258 new FlexError( FlexError.CRITICAL, Resources.get(6232) + " (" + data.getTransId() + ")", IDENTIFIER, 7046 );
259 }
260 finally
261 {
262 // Dispose the checkInGateway
263 checkInGateway.dispose();
264 }
265
266 // Roll back (in file system) those files that failed to process
267 rollBackFiles( vBadRecords, vBadStates );
268 nGlobalState = FILES_ROLLED_BACK;
269
270 cleanUpTempDir();
271 nGlobalState = TEMPDIR_CLEANED;
272
273 // After rolling back and cleanup, if this thread was interrupted, rethrow the exception
274 if ( isInterrupted() )
275 throw new InterruptedException();
276
277 ActionResult actionResult;
278 if ( vBadRecords.size() > 0 )
279 {
280 actionResult = new ActionResult(false);
281 actionResult.setBadRecords( vBadRecords );
282 }
283 else
284 actionResult = new ActionResult(true);
285
286 data.setRecords( vGoodRecords );
287 actionResult.setId( data.getTransId() );
288 actionResult.setData( data );
289 return actionResult;
290 }
291
292 /**
293 * Check if another thread request this thread to be interrupted.
294 */
295 private boolean isInterrupted()
296 {
297 if ( !bInterrupted && abortManager() )
298 {
299 bInterrupted = true;
300 bContinue = false;
301 }
302 return bInterrupted;
303 }
304
305 protected ActionResult getResultObjectOnAbnormalEnding()
306 {
307 if ( nGlobalState < TEMPDIR_CLEANED )
308 {
309 // Cleanup the temp directory
310 cleanUpTempDir();
311
312 if ( nGlobalState < FILES_ROLLED_BACK )
313 {
314 // Roll back in file system the records in vBadRecords
315 rollBackFiles( vBadRecords, vBadStates );
316
317 //If failed abnormally and database has not been updated, lets try to update;
318 // records in vGoodRecords should be updated to check-in, records in vBadRecords
319 // and records in vRecords (not processed yet) should be update to check-out.
320 if ( nGlobalState < DATABASE_UPDATED )
321 {
322 if ( vRecords.size() > 0 )
323 {
324 for ( int i = 0; i < vRecords.size(); i++ )
325 {
326 vBadRecords.addElement( (AssetRecordData) vRecords.elementAt(i) );
327 if ( nGlobalState < ASSETS_CHECKED_IN )
328 vBadStates.addElement( new Integer(DEFAULTVIEW_COPIED) );
329 else
330 vBadStates.addElement( new Integer(ASSETS_CHECKED_IN) );
331 }
332 }
333 try
334 {
335 checkInGateway.connect();
336 updateDatabase( vGoodRecords, vBadRecords );
337 }
338 catch ( TransactionFailedException rtfe )
339 {
340 // Roll back all good files; lets set the state for all records
341 Vector vStates = new Vector( vGoodRecords.size() );
342 for ( int i = 0; i < vGoodRecords.size(); i++ )
343 vStates.addElement( new Integer(ASSETS_CHECKED_IN) );
344 rollBackFiles( vGoodRecords, vStates );
345 }
346 finally
347 {
348 // Dispose the checkInGateway
349 checkInGateway.dispose();
350 }
351 }
352 }
353 }
354 ActionResult actionResult = null;
355 if ( vBadRecords.size() > 0 )
356 {
357 actionResult = new ActionResult(false);
358 actionResult.setBadRecords( vBadRecords );
359 }
360 else
361 actionResult = new ActionResult(true);
362
363 actionResult.setId( data.getTransId() );
364 return actionResult;
365 }
366
367 /**
368 * Set the status in the database to in-progress
369 */
370 private boolean setStatusToInProgress()
371 throws TransactionFailedException
372 {
373 long[] laBadAssets = checkInGateway.updateToInProcessCheckIn( data );
374 if ( laBadAssets == null )
375 return false;
376
377 if ( laBadAssets.length > 0 )
378 {
379 // if all records failed, return false
380 if ( laBadAssets.length == vRecords.size() )
381 return false;
382 else
383 {
384 // remove the records that could not be updated
385 AssetRecordData record;
386 for ( int i = 0; i < laBadAssets.length; i++ )
387 {
388 for ( Iterator it = vRecords.iterator(); it.hasNext(); )
389 {
390 record = (AssetRecordData) it.next();
391 if ( record.getRecordId() == laBadAssets[i] )
392 {
393 vBadRecords.addElement( record );
394 it.remove();
395 }
396 }
397 }
398 }
399 }
400 return true;
401 }
402
403 private void moveOriginalToVersionsDir( AssetRecordData record )
404 {
405 // Set the tempData object used all along this service
406 ActionData tempData = (ActionData)data.clone();
407 tempData.setRecords( null ); // reset records
408 AssetRecordData tempRecord = (AssetRecordData)record.clone();
409 String sNewLocation = tempRecord.getLocation() + ".versions" + fileSeparator + tempRecord.getString( ActionPropertiesI.VERSION_NUMBER_PREVIOUS ) + fileSeparator;
410 tempRecord.setString( ActionPropertiesI.DESTINATION_SERVER, tempRecord.getServer() );
411 tempRecord.setString( ActionPropertiesI.DESTINATION_LOCATION, sNewLocation );
412 // set Keep Resource fork to true so version file maintains its resource fork
413 tempRecord.setBoolean( ActionPropertiesI.KEEP_RESOURCEFORK, new Boolean(true) );
414 // set is MacBinary to false
415 tempRecord.setBoolean( ActionPropertiesI.MACBINARY_FORMAT, new Boolean(false) );
416
417 tempData.addRecord( tempRecord );
418 executeService( ServicesI.MOVE_SERVICE, tempData );
419
420 // Set the version server, location and filename
421 record.setString( ActionPropertiesI.VERSION_SERVER, record.getServer() );
422 record.setString( ActionPropertiesI.VERSION_LOCATION, sNewLocation );
423 record.setString( ActionPropertiesI.VERSION_FILENAME, record.getFileName() );
424 record.setLong( ActionPropertiesI.VERSION_FILESIZE, record.getFileSize() );
425 }
426
427 private void copyNewVersionIntoOriginal( AssetRecordData record )
428 {
429 // Set the tempData object used all along this service
430 ActionData tempData = (ActionData)data.clone();
431 AssetRecordData tempRecord = (AssetRecordData)record.clone();
432
433 int nAppleTalkVendor = RsrcForkConstantsI.NONE;
434 boolean bIsMacBinary = false;
435 try
436 {
437 nAppleTalkVendor = record.getAppleTalkVendor().intValue();
438 bIsMacBinary = record.isMacBinaryFormat().booleanValue();
439 }
440 catch( NullPointerException npe ) {}
441
442 String sSourceLocation = record.getString( ActionPropertiesI.SOURCE_LOCATION );
443 if ( sSourceLocation != null && PathAnalyzer.getRemoteFileProtocol(sSourceLocation) != null )
444 {
445 record.setString( ActionPropertiesI.SOURCE_SERVER, PathAnalyzer.getServerName(sSourceLocation) );
446 sSourceLocation = PathAnalyzer.getLocalPath(sSourceLocation);
447 record.setString( ActionPropertiesI.SOURCE_LOCATION, sSourceLocation );
448 }
449
450 // Get the source location and set this as the input path for the next service
451 String sPath = PathBuilder.constructFilePath( record.getString( ActionPropertiesI.SOURCE_SERVER ),
452 sSourceLocation,
453 record.getString( ActionPropertiesI.SOURCE_FILENAME ) );
454
455 // Determine if the new file is in a server other than the FlexDBServer. If so and ONLY if bIsMacBinary == true,
456 // we will need to copy the file to the temp location of the FlexDBServer and from there split the MacBinary
457 // check if sServer is the same as this server
458 if ( !FlexDbServerHost.isLocalHost( PathAnalyzer.getServerDNS(sPath) ) && bIsMacBinary )
459 {
460 if ( !(new XFileCopy()).copy( sPath, sTempDir + PathAnalyzer.getFileName(sPath) ) )
461 {
462 // 7048=Unable to transfer file from %%1 to FlexDBServer. Check-out failed.
463 new FlexError( FlexError.CRITICAL, Resources.get(6232) + " (" + data.getTransId() + ")", IDENTIFIER, 7048, new String[] { PathAnalyzer.getServerDNS(sPath) } );
464 bContinue = false;
465 return;
466 }
467 else
468 {
469 // Set the new source location to be the temp directory; also set bIsLocationInServer to false
470 // to cleanup temp directory at the end
471 record.setString( ActionPropertiesI.SOURCE_SERVER, FlexDbServerHost.getLocalHostName() );
472 record.setString( ActionPropertiesI.SOURCE_LOCATION, sTempDir );
473 record.setString( ActionPropertiesI.SOURCE_FILENAME, PathAnalyzer.getFileName(sPath) );
474 record.setBoolean( ActionPropertiesI.IS_LOCATION_IN_SERVER, new Boolean(false) );
475 // Update sPath with the new file path
476 sPath = PathBuilder.constructFilePath( record.getString( ActionPropertiesI.SOURCE_SERVER ),
477 record.getString( ActionPropertiesI.SOURCE_LOCATION ),
478 record.getString( ActionPropertiesI.SOURCE_FILENAME ) );
479 }
480 }
481
482 FlexXFile source = new FlexXFile( sPath );
483
484 // Get the asset location and format it according to the standard in Flexstor; that is:
485 // No leading slash, but trailing slash
486 String sLocation = PathAnalyzer.getLocalParent( sPath );
487 sLocation = PathBuilder.addFileSeparators( sLocation, false, true );
488 sLocation = PathBuilder.removeFileSeparators( sLocation, true, false );
489
490 tempRecord.setServer( PathAnalyzer.getServerName( sPath ) );
491 tempRecord.setLocation( sLocation );
492 tempRecord.setFileName( PathAnalyzer.getFileName( sPath ) );
493 record.setLong( ActionPropertiesI.SOURCE_FILESIZE, new Long(source.length()) );
494 tempRecord.setFileSize( record.getLong( ActionPropertiesI.SOURCE_FILESIZE ) );
495
496 // Now we need to check if this file is a MacBinary or not. If it is then we copy the file
497 // by doing a separteFork; if it is not then we proceed as normal
498 if ( bContinue )
499 {
500 if ( nAppleTalkVendor > RsrcForkConstantsI.NONE && bIsMacBinary )
501 {
502 tempData.setRecords( null ); // reset records
503 tempRecord.setDestinationLocation( PathBuilder.constructPath( record.getServer(), record.getLocation(), true ) );
504 tempData.addRecord( tempRecord );
505 tempData.setInteger( ActionData.RESOURCEFORK_ACTION, new Integer(RsrcForkConstantsI.SEPARATE_FORKS) );
506 executeService( ServicesI.RESOURCEFORK_SERVICE, tempData );
507 }
508 else
509 {
510 tempData.setRecords( null ); // reset records
511 // The destination location will be the original location of the file.
512 tempRecord.setDestinationLocation( PathBuilder.constructPath( record.getServer(), record.getLocation(), true ) );
513 tempRecord.setDestinationFileName( record.getFileName() );
514 tempData.addRecord( tempRecord );
515
516 executeService( ServicesI.COPY_SERVICE, tempData );
517 }
518 // After this is done we should change the file size of the original record for
519 // the one of the newly created file.
520 record.setFileSize( record.getLong( ActionPropertiesI.SOURCE_FILESIZE ) );
521
522 // Also get the modification date of the file. Use the file in the temp location.
523 record.setString( ActionPropertiesI.MODIFICATION_DATE, (new Date(source.lastModified())).toString() );
524 }
525 }
526
527 /**
528 * This method regenerates the lowres file for a highres.
529 * For this, we first query the database to find out if this asset has a lowres child;
530 * if it does, then we call the LowresService to recreate the lowres asset.
531 * NOTE: The service takes as input the highres asset, not the lowres child.
532 */
533 private void updateLowres( AssetRecordData record )
534 throws TransactionFailedException
535 {
536 // Call the bean and find out if there are children to add.
537 ActionData childActionData = checkInGateway.getChildrenByAssetRole( LOWRES, record );
538 Vector vChildRecords = childActionData.getRecords();
539 if ( vChildRecords != null && vChildRecords.size() > 0 )
540 {
541 // There should be only one lowres for this asset; so there should be a single item in the Vector
542 AssetRecordData childRecord = (AssetRecordData)vChildRecords.elementAt(0);
543
544 // Set the tempData object and add the highres asset to it
545 ActionData tempData = (ActionData)data.clone();
546 tempData.addRecord( record );
547
548 // Add the child to the AssetRecordData
549 record.addChildRecord( childRecord );
550
551 // VersionNo needs to be set always, even if we won't keep the lowres version
552 childRecord.setString( ActionPropertiesI.VERSION_NUMBER, record.getString( ActionPropertiesI.VERSION_NUMBER ) );
553
554 // Now lets find out if we need to keep the lowres for the version asset
555 boolean bKeepLowres = false;
556 try { bKeepLowres = record.getBoolean( ActionPropertiesI.KEEP_LOWRES ).booleanValue(); }
557 catch ( NullPointerException npe ) {}
558 if ( bKeepLowres )
559 {
560 // Set the VersionXXXXX and other info needed in the bean
561 childRecord.setString( ActionPropertiesI.VERSION_SERVER, childRecord.getServer() );
562 childRecord.setString( ActionPropertiesI.VERSION_FILENAME, childRecord.getFileName() );
563 childRecord.setLong( ActionPropertiesI.VERSION_FILESIZE, childRecord.getFileSize() );
564 childRecord.setString( ActionPropertiesI.CHECKIN_DATETIME, record.getString( ActionPropertiesI.CHECKIN_DATETIME ) );
565
566 String sLocation = childRecord.getLocation();
567 String sNewLocation = sLocation + ".versions" + fileSeparator + record.getString( ActionPropertiesI.VERSION_NUMBER_PREVIOUS )
568 + fileSeparator;
569 childRecord.setString( ActionPropertiesI.VERSION_LOCATION, sNewLocation );
570
571 // Create a new record pointing to the highres in .versions in order to create its lowres
572 AssetRecordData versionRecord = (AssetRecordData)record.clone();
573 versionRecord.setLocation( record.getString( ActionPropertiesI.VERSION_LOCATION ) );
574 tempData.addRecord( versionRecord );
575 }
576
577 if ( tempData.getRecords() != null && tempData.getRecords().size() > 0 )
578 {
579 tempData.setInteger( "lowres_action", new Integer( LowresConstants.CREATE_LOWRES ) );
580 executeService( ServicesI.LOWRES_SERVICE, tempData );
581 }
582 }
583 }
584
585 private void copyDefaultViewToVersionDir( AssetRecordData record )
586 throws TransactionFailedException
587 {
588 // Call the bean and find out if there are children to add.
589 AssetRecordData childRecord = (AssetRecordData)checkInGateway.getDefaultViewAsset( record );
590
591 if ( childRecord != null )
592 {
593 // Set the tempData object used all along this service
594 ActionData tempData = (ActionData)data.clone();
595
596 // Add the child to the AssetRecordData
597 record.addChildRecord( childRecord );
598 record.setDefaultViewAssetId( new Long(childRecord.getAssetId()) );
599
600 String sLocation = childRecord.getLocation();
601 String sNewLocation = null;
602 // If location contains the string "defaultthumbnail" do not copy but create
603 // new asset pointing to the same defaultthumbnail.
604 if ( sLocation.indexOf( "defaultthumbnail" ) == -1 )
605 {
606 sNewLocation = sLocation + ".versions" + fileSeparator + record.getString( ActionPropertiesI.VERSION_NUMBER_PREVIOUS ) + fileSeparator;
607 childRecord.setString( ActionPropertiesI.DESTINATION_SERVER, childRecord.getServer() );
608 childRecord.setDestinationLocation( sNewLocation );
609 childRecord.setString( ActionPropertiesI.VERSION_SERVER, childRecord.getServer() );
610 childRecord.setString( ActionPropertiesI.VERSION_LOCATION, sNewLocation );
611 childRecord.setString( ActionPropertiesI.VERSION_FILENAME, childRecord.getFileName() );
612 // set Keep Resource fork to true so lowres version files maintains its resource fork
613 childRecord.setBoolean( ActionPropertiesI.KEEP_RESOURCEFORK, new Boolean(true) );
614 // set is MacBinary to false
615 childRecord.setBoolean( ActionPropertiesI.MACBINARY_FORMAT, new Boolean(false) );
616 tempData.addRecord( childRecord );
617 }
618 else
619 {
620 childRecord.setString( ActionPropertiesI.VERSION_SERVER, childRecord.getServer() );
621 childRecord.setString( ActionPropertiesI.VERSION_LOCATION, childRecord.getLocation() );
622 childRecord.setString( ActionPropertiesI.VERSION_FILENAME, childRecord.getFileName() );
623
624 // To avoid creating thumbnails in the defaultthumbnail directory, reset the values of server, location and filename
625 childRecord.removeObject( ActionPropertiesI.SERVER );
626 childRecord.removeObject( ActionPropertiesI.LOCATION );
627 childRecord.removeObject( ActionPropertiesI.FILENAME );
628 }
629 // Set the VersionXXXXX and other info needed in the bean
630 childRecord.setString( ActionPropertiesI.VERSION_NUMBER, record.getString( ActionPropertiesI.VERSION_NUMBER ) );
631 childRecord.setLong( ActionPropertiesI.VERSION_FILESIZE, childRecord.getFileSize() );
632 childRecord.setString( ActionPropertiesI.CHECKIN_DATETIME, record.getString( ActionPropertiesI.CHECKIN_DATETIME ) );
633
634 if ( tempData.getRecords() != null && tempData.getRecords().size() > 0 )
635 executeService( ServicesI.COPY_SERVICE, tempData );
636 // If we were unable to copy the default view (thumbnail) we should still
637 // continue with the check in process. We don't need to be concerned about
638 // resetting to true a bContinue value that failed elsewhere in the checkIn
639 // process, because the process would not have made it to this method if it
640 // failed elsewhere.
641 if ( bContinue == false )
642 {
643 bContinue = true;
644 }
645 }
646 }
647
648 private void rollBackFiles( Vector vBadRecords, Vector vBadStates )
649 {
650 if ( vBadRecords.size() > 0 )
651 {
652 Vector vOriginal = new Vector();
653 Vector vDefaultView = new Vector();
654 Vector vOriginalLowres = new Vector(); // holds lowres for original assets
655 Vector vVersionLowres = new Vector(); // holds lowres for version assets
656 AssetRecordData record = null;
657 for ( int i = 0; i < vBadRecords.size(); i++ )
658 {
659 record = (AssetRecordData) vBadRecords.elementAt(i);
660 // According to the state, add this record to one or more
661 // rollback methods.
662 switch ( ((Integer) vBadStates.elementAt(i)).intValue() )
663 {
664 case ASSETS_CHECKED_IN:
665 case DEFAULTVIEW_COPIED:
666 rollBackDefaultView( true, vDefaultView, record );
667 case LOWRES_UPDATED:
668 if ( hasLowres( record ) )
669 rollBackLowres( true, vOriginalLowres, vVersionLowres, record );
670 case NEW_VERSION_COPIED:
671 case ORIGINAL_MOVED:
672 rollBackOriginal( true, vOriginal, null, record );
673 break;
674 }
675 }
676 rollBackDefaultView( false, vDefaultView, null );
677 rollBackLowres( false, vOriginalLowres, vVersionLowres, null );
678 rollBackOriginal( false, vOriginal, vOriginalLowres, null );
679 }
680 }
681
682 private void rollBackOriginal( boolean bProcessRecord, Vector vRecords, Vector vLowres, AssetRecordData record )
683 {
684 if ( bProcessRecord )
685 {
686 AssetRecordData tempRecord = (AssetRecordData)record.clone();
687 String sNewLocation = tempRecord.getLocation();
688 tempRecord.setString( ActionPropertiesI.DESTINATION_SERVER, tempRecord.getServer() );
689 tempRecord.setDestinationLocation( sNewLocation );
690 // set Keep Resource fork to true so files maintains its resource fork
691 tempRecord.setBoolean( ActionPropertiesI.KEEP_RESOURCEFORK, new Boolean(true) );
692 // set is MacBinary to false
693 tempRecord.setBoolean( ActionPropertiesI.MACBINARY_FORMAT, new Boolean(false) );
694 // Set the version server, location and filename
695 tempRecord.setServer( tempRecord.getString( ActionPropertiesI.VERSION_SERVER ) );
696 tempRecord.setLocation( tempRecord.getString( ActionPropertiesI.VERSION_LOCATION ) );
697 tempRecord.setFileName( tempRecord.getString( ActionPropertiesI.VERSION_FILENAME ) );
698 tempRecord.setFileSize( tempRecord.getLong( ActionPropertiesI.VERSION_FILESIZE ) );
699 vRecords.addElement( tempRecord );
700 }
701 else if ( vRecords.size() > 0 )
702 {
703 // Set the tempData object used all along this service
704 ActionData tempData = (ActionData)data.clone();
705 tempData.setRecords( vRecords ); // Set records
706 executeService( ServicesI.MOVE_SERVICE, tempData );
707
708 // Find out if we need to update the lowres for these assets
709 if ( vLowres.size() > 0 )
710 {
711 tempData.setRecords( vLowres );
712 tempData.setInteger( "lowres_action", new Integer(LowresConstants.CREATE_LOWRES) );
713 executeService( ServicesI.LOWRES_SERVICE, tempData );
714 }
715 }
716 }
717
718 private void rollBackLowres( boolean bProcessRecord, Vector vOriginals, Vector vVersions, AssetRecordData record )
719 {
720 if ( bProcessRecord )
721 {
722 vOriginals.addElement( record );
723 // Now lets find out if we need to keep the lowres for the version asset
724 boolean bKeepLowres = false;
725 try { bKeepLowres = record.getBoolean( ActionPropertiesI.KEEP_LOWRES ).booleanValue(); }
726 catch ( NullPointerException npe ) {}
727 if ( bKeepLowres )
728 {
729 // Create a new record pointing to the highres in .versions in order to create its lowres
730 AssetRecordData versionRecord = (AssetRecordData)record.clone();
731 versionRecord.setLocation( record.getString( ActionPropertiesI.VERSION_LOCATION ) );
732 vVersions.addElement( versionRecord );
733 }
734 }
735 else if ( !vOriginals.isEmpty() )
736 {
737 // Set the tempData object used all along this service
738 ActionData tempData = (ActionData)data.clone();
739
740 // vVersions has elements only if vOriginals has.
741 // Add the elements to vVersions instead of vOriginals, because vOriginals is needed
742 // in rollBackOriginals(...), called after this method.
743 if ( !vVersions.isEmpty() )
744 {
745 for ( int i = 0; i < vOriginals.size(); i++ )
746 vVersions.addElement( vOriginals.elementAt(i) );
747
748 tempData.setRecords( vVersions );
749 }
750 else
751 tempData.setRecords( vOriginals ); // Set records
752
753 tempData.setInteger( "lowres_action", new Integer(LowresConstants.DELETE_LOWRES) );
754 executeService( ServicesI.LOWRES_SERVICE, tempData );
755 }
756 }
757
758 private void rollBackDefaultView( boolean bProcessRecord, Vector vRecords, AssetRecordData record )
759 {
760 if ( bProcessRecord )
761 {
762 AssetRecordData thumbRecord = getDefaultViewRecord(record);
763 if ( thumbRecord != null )
764 {
765 thumbRecord = (AssetRecordData) thumbRecord.clone();
766 thumbRecord.setDestinationLocation( PathBuilder.constructPath( thumbRecord.getServer(), thumbRecord.getLocation(), true ) );
767 // Set the server, location and filename
768 thumbRecord.setServer( thumbRecord.getString( ActionPropertiesI.VERSION_SERVER ) );
769 thumbRecord.setLocation( thumbRecord.getString( ActionPropertiesI.VERSION_LOCATION ) );
770 thumbRecord.setFileName( thumbRecord.getString( ActionPropertiesI.VERSION_FILENAME ) );
771 thumbRecord.setFileSize( thumbRecord.getLong( ActionPropertiesI.VERSION_FILESIZE ) );
772 // set Keep Resource fork to true so lowres files maintains its resource fork
773 thumbRecord.setBoolean( ActionPropertiesI.KEEP_RESOURCEFORK, new Boolean(true) );
774 // set is MacBinary to false
775 thumbRecord.setBoolean( ActionPropertiesI.MACBINARY_FORMAT, new Boolean(false) );
776 vRecords.addElement( thumbRecord );
777 }
778 }
779 else if ( vRecords.size() > 0 )
780 {
781 // Set the tempData object used all along this service
782 ActionData tempData = (ActionData)data.clone();
783 tempData.setRecords( vRecords ); // Set records
784 executeService( ServicesI.MOVE_SERVICE, tempData );
785 }
786 }
787
788 private void regenerateAssetsInfo( Vector vGoodRecords )
789 {
790 Vector vRegenerateRecords = new Vector();
791 AssetRecordData record = null;
792 for ( int i = 0; i < vGoodRecords.size(); i++ )
793 {
794 record = (AssetRecordData) vGoodRecords.elementAt(i);
795 try
796 {
797 if ( record.getBoolean( ActionPropertiesI.REGENERATE_THUMBNAIL ).booleanValue() == true )
798 vRegenerateRecords.addElement( record );
799 }
800 catch ( NullPointerException npe ) {}
801 }
802
803 if ( vRegenerateRecords.size() > 0 )
804 {
805 // Set the tempData object used all along this service
806 ActionData tempData = (ActionData)data.clone();
807 tempData.setRecords( vRegenerateRecords );
808 executeService( ServicesI.IMPORT_ACTIONDATA_SERVICE, tempData );
809 }
810 }
811
812 private void checkInAssets( Vector vGoodRecords )
813 throws TransactionFailedException
814 {
815 ActionData checkInDummyData = (ActionData)data.clone();
816 checkInDummyData.setRecords( vGoodRecords );
817 checkInGateway.checkInAssets( checkInDummyData );
818 }
819
820 private void updateDatabase( Vector vGoodRecords, Vector vBadRecords )
821 throws TransactionFailedException
822 {
823 if ( vGoodRecords.size() > 0 )
824 {
825 ActionData goodData = (ActionData)data.clone();
826 goodData.setRecords( vGoodRecords );
827 Diagnostic.trace(Diagnostic.APPSERVER_SERVICES, "Doing checkInAsset in the database!!!");
828 try
829 {
830 checkInGateway.updateCheckInStatus( goodData );
831 }
832 catch ( TransactionFailedException rtfe )
833 {
834 // If this fails, add elements of vGoodRecords to vBadRecords so we roll them
835 // back
836 for ( int i = 0; i < vGoodRecords.size(); i++ )
837 {
838 vBadRecords.addElement( (AssetRecordData) vGoodRecords.elementAt(i) );
839 vBadStates.addElement( new Integer(ASSETS_CHECKED_IN) );
840 }
841 vGoodRecords.removeAllElements();
842 }
843 }
844 if ( vBadRecords.size() > 0 )
845 {
846 ActionData badData = (ActionData)data.clone();
847 // If the global state is less than ASSETS_CHECKED_IN, we know that version records were not created
848 // in the database for any of the bad assets and it is safe to call the rollBackInProcessCheckIn with
849 // a 'false' argument.
850 // However if the global state is equal or greater than ASSETS_CHECKED_IN, we need to parse through
851 // the list of bad records to find out which one failed before calling the checkInAssets() (and pass
852 // false in the argument) and for which one we called checkInAssets() (and pass true in the argument)
853 if ( nGlobalState < ASSETS_CHECKED_IN )
854 {
855 badData.setRecords( vBadRecords );
856 Diagnostic.trace(Diagnostic.APPSERVER_SERVICES, "Doing cancelCheckInAssets in the database!!!");
857 checkInGateway.rollbackInProcessCheckIn( badData, false ); // Versions not created
858 }
859 else
860 {
861 Vector vFailedBeforeCheckedIn = new Vector();
862 Vector vFailedAfterCheckedIn = new Vector();
863
864 int nState;
865 for ( int i = 0; i < vBadStates.size(); i++ )
866 {
867 nState = ((Integer)vBadStates.elementAt(i)).intValue();
868 if ( nState < ASSETS_CHECKED_IN )
869 vFailedBeforeCheckedIn.addElement( vBadRecords.elementAt(i) );
870 else
871 vFailedAfterCheckedIn.addElement( vBadRecords.elementAt(i) );
872 }
873
874 if ( vFailedBeforeCheckedIn.size() > 0 )
875 {
876 badData.setRecords( vFailedBeforeCheckedIn );
877 Diagnostic.trace(Diagnostic.APPSERVER_SERVICES, "Doing cancelCheckInAssets in the database!!!");
878 checkInGateway.rollbackInProcessCheckIn( badData, false );
879 }
880 if ( vFailedAfterCheckedIn.size() > 0 )
881 {
882 badData.setRecords( vFailedAfterCheckedIn );
883 Diagnostic.trace(Diagnostic.APPSERVER_SERVICES, "Doing cancelCheckInAssets in the database!!!");
884 checkInGateway.rollbackInProcessCheckIn( badData, true );
885 }
886 }
887 }
888 }
889
890 private void cleanUpTempDir()
891 {
892 // Set the tempData object used all along this service
893 ActionData tempData = (ActionData)data.clone();
894 // Remove all files from the /tmp/TransId directory; including the directory if empty
895 tempData.setRecords( null );
896 Vector vRecords = data.getRecords();
897
898 AssetRecordData tempRecord;
899 for ( int i = 0; i < vRecords.size(); i++ )
900 {
901 tempRecord = (AssetRecordData) vRecords.elementAt(i);
902
903 boolean bIsLocationInServer = true;
904 try { bIsLocationInServer = tempRecord.getBoolean( ActionPropertiesI.IS_LOCATION_IN_SERVER ).booleanValue(); }
905 catch ( NullPointerException npe ) {}
906 if ( !bIsLocationInServer )
907 {
908 // Location in server is the temp directory; delete files
909 // Get the source location and set this as the input path for the next service
910 tempRecord.setServer( ServerList.getServerName( tempRecord.getString(ActionPropertiesI.SOURCE_SERVER) ) );
911 tempRecord.setLocation( tempRecord.getString(ActionPropertiesI.SOURCE_LOCATION) );
912 tempRecord.setFileName( tempRecord.getString(ActionPropertiesI.SOURCE_FILENAME) );
913 tempRecord.setFileSize( tempRecord.getLong( ActionPropertiesI.SOURCE_FILESIZE ) );
914 tempData.addRecord( tempRecord );
915 }
916 }
917
918 if ( tempData.getRecords() != null )
919 executeService( ServicesI.DELETE_SERVICE, tempData );
920 }
921
922 private void executeService( String sServiceName, ActionData data )
923 {
924 try
925 {
926 ActionResult result = doService( sServiceName, data );
927 if ( result == null )
928 bContinue = false;
929 else
930 bContinue = result.isSuccess();
931 }
932 catch( SrvcNotAvailException e )
933 {
934 //6232=Check-In Service
935 new FlexError(FlexError.CRITICAL, Resources.get(6232), IDENTIFIER, e);
936 bContinue = false;
937 }
938 }
939
940 private AssetRecordData getDefaultViewRecord( AssetRecordData record )
941 {
942 Vector vChildren = record.getChildrenRecords();
943 if ( vChildren != null )
944 {
945 long nDefaultViewAssetId = record.getDefaultViewAssetId().longValue();
946 AssetRecordData child;
947 for ( int i = 0; i < vChildren.size(); i++ )
948 {
949 child = (AssetRecordData)vChildren.elementAt(i);
950 if ( child.getAssetId() == nDefaultViewAssetId )
951 return child;
952 }
953 }
954 return null;
955 }
956
957 private boolean hasLowres( AssetRecordData record )
958 {
959 Vector vChildren = record.getChildrenRecords();
960 if ( vChildren != null )
961 {
962 for ( int i = 0; i < vChildren.size(); i++ )
963 {
964 Integer nRoleId = ((AssetRecordData)vChildren.elementAt(i)).getRoleId();
965 if ( nRoleId.intValue() == LOWRES )
966 return true;
967 }
968 }
969 return false;
970 }
971 } // end of class