Source code: com/flexstor/flexdbserver/services/asset/ImportAssetService.java
1 /*
2 * ImportAssetService.java
3 *
4 * Copyright $Date: 2003/08/11 02:22:29 $ 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.util.Enumeration;
14 import java.util.Hashtable;
15 import java.util.Vector;
16
17 import com.flexstor.common.data.ActionData;
18 import com.flexstor.common.data.ActionResult;
19 import com.flexstor.common.data.ejb.disguiserecord.DisguiseAssetRecordData;
20 import com.flexstor.common.data.ejb.disguiserecord.DisguiseBucketRecordData;
21 import com.flexstor.common.data.ejb.disguiserecord.DisguiseRecordData;
22 import com.flexstor.common.errorlogger.FlexError;
23 import com.flexstor.common.importprocessor.ImportData;
24 import com.flexstor.common.importprocessor.ImportResult;
25 import com.flexstor.common.importprocessor.ResultListener;
26 import com.flexstor.common.resources.Resources;
27 import com.flexstor.common.services.ServiceBrokerI;
28 import com.flexstor.common.services.ServiceListenerI;
29 import com.flexstor.common.threadmgr.ThreadCallbackI;
30 import com.flexstor.common.threadmgr.ThreadConsumerI;
31 import com.flexstor.common.util.Diagnostic;
32 import com.flexstor.flexdbserver.importprocessor.ImportProcessor;
33 import com.flexstor.flexdbserver.services.Service;
34 import com.flexstor.flexdbserver.services.ServiceContext;
35 import com.flexstor.flexdbserver.services.ServiceManager;
36 import com.flexstor.flexdbserver.transactionmanager.TransMngImport;
37
38 /**
39 * <P>
40 * ImportAssetService <BR>
41 * <BLOCKQUOTE>
42 * Manages the entire process of importing assets into the database. This service reads from the
43 * input control (*.ctl) file a list of services to be performed against all assets (preservices, for example
44 * assigning roles and types to each asset); then it divides the assets in groups by role and type
45 * and performs the set of services specified for each group in the roletype_services.config file. Finally,
46 * if specified in the roletype_services.config file, it will import the assets into the database.
47 * </BLOCKQUOTE>
48 * </P>
49 *
50 * <P>
51 * Input Data Object <BR>
52 * <BLOCKQUOTE>
53 * com.flexstor.common.importprocessor.ImportData
54 * </BLOCKQUOTE>
55 * </P>
56 *
57 * <P>
58 * Output Data Object <BR>
59 * <BLOCKQUOTE>
60 * com.flexstor.common.importprocessor.ImportResult
61 * </BLOCKQUOTE>
62 * </P>
63 */
64 public class ImportAssetService
65 implements Service, ThreadCallbackI
66 {
67 // To get the version number from MKS
68 public final static String IDENTIFIER="$Id: ImportAssetService.java,v 1.4 2003/08/11 02:22:29 aleric Exp $";
69
70 private ServiceBrokerI serviceBroker;
71 private int id = -1;
72 private String sThisService = "";
73 private ImportData importData = null;
74 private ImportData subImportDataReturned = null;
75 private int nManagerRunning = 0;
76 private ServiceListenerI listener = null; // The listener of this service
77 private String sServiceType = ""; //Valid values: PreService, PostService or Service
78 private String sSubTransId = ""; //The Transaction id for this sub transaction
79 private boolean bContinue = true;
80
81 /**
82 * Calls before the service is initialized (before initData is called) to
83 * pass information about the environment in which the service is running.
84 * This environment consists of information about the properties set for the
85 * service in one of these files (services.config, roletype_services.config,
86 * or *.ctl), plus methods to access other information such as an instance
87 * of the service broker to invoke other services, the transaction id for
88 * the service, file separator character and local path for the installation
89 * directory and configuration directory.
90 *
91 * @param context Holds information about the environment in which the service
92 * is running.
93 */
94 public void setServiceContext( ServiceContext context )
95 {
96 serviceBroker = context.getServiceBroker();
97 id = context.getTransactionId();
98 }
99
100 /**
101 * A data initialization method called at the beginning of the service.
102 * The input argument, ActionData must be cast into its subclass, ImportData
103 * in order to extract the AssetService specific data.
104 **/
105 public void initData(ActionData actionData)
106 {
107 importData = (ImportData) actionData;
108 listener = importData.getServiceListener();
109 sSubTransId = importData.getTransID();
110 //5560=Import Asset Service
111 sThisService = Resources.get(5560) + " (" + sSubTransId + ")";
112 }
113
114 /**
115 * The start of the Asset Service.
116 **/
117 public synchronized ActionResult go()
118 {
119 boolean bLockHotDir = false;
120 String sHotDirToLock = "";
121
122 // This code will be enclosed in a try/finally block to ensure that
123 // when a hot directory is locked, no matter what, it will be released
124 try
125 {
126 // Check if it is necessary to lock the hot directory
127 // Retrieve the LockHotdir property from the *ctl file
128 bLockHotDir = (new Boolean(importData.getCtlDataRef().getValuePerKey("LOCKHOTDIR"))).booleanValue();
129 if ( bLockHotDir )
130 {
131 // Retrieve the base path of the hot directory to be locked
132 sHotDirToLock = importData.getCtlDataRef().getValuePerKey("TOP");
133 ImportProcessor.lockHotDir(sHotDirToLock);
134 }
135
136 TransMngImport tmImport = new TransMngImport( id );
137
138 // Run Pre-Services
139 // Start an instance of the Asset Service Manager in a different thread and waits
140 // for it to finish; if something wrong happens, abort the Import Asset Service
141 try
142 {
143 sServiceType = AssetServiceManager.PRESERVICES;
144 (new AssetServiceManager(sServiceType, importData, this)).startManager();
145 this.wait();
146
147 // Replace the original import data object with the one updated by the pre-services
148 importData = subImportDataReturned;
149 }
150 catch (InterruptedException ie)
151 {
152 // Remove the assets from the ASSETS_INPROCESS table and remove this persisted
153 // transaction from TransList.per
154 tmImport.setTransactionCompletedState();
155 new FlexError(FlexError.CRITICAL, sThisService, IDENTIFIER, ie);
156 notifyListener();
157 return new ImportResult(false);
158 }
159 catch (AssetServiceManagerException rasme)
160 {
161 // Remove the assets from the ASSETS_INPROCESS table and remove this persisted
162 // transaction from TransList.per
163 tmImport.setTransactionCompletedState();
164 new FlexError(FlexError.CRITICAL, sThisService, IDENTIFIER, rasme);
165 notifyListener();
166 return new ImportResult(false);
167 }
168
169 // After all preservices are completed, create subsets of ImportData per each file type
170 Hashtable hImportDataSubSet = null;
171 if ( bContinue )
172 hImportDataSubSet = createImportDataSubSets();
173
174 if (hImportDataSubSet != null)
175 {
176 // Set sServiceType to "Service" to indicate that the updateImportData() method
177 // must be performed.
178 sServiceType = "Service";
179 // Set the counter of manager running to zero; as it could be modified by the
180 // preservices
181 nManagerRunning = 0;
182
183 // Create one thread per ImportDataSubSet and start a Remote Asset Service Manager
184 // synchronized to protect integrity of hImportDataSubSet and to make sure we start
185 //all the threads before getting any response back from observables.
186 for (Enumeration e = hImportDataSubSet.keys(); e.hasMoreElements(); )
187 {
188 String sType = (String) e.nextElement();
189 ImportData importDataSubSet = (ImportData) hImportDataSubSet.get(sType);
190 // Create a new transaction manager for this object and set the state to
191 // IMPORT_INPROCESS_TABLE_UPDATE_STATE for rollback purposes. Assets were already
192 // added to the ASSETS_INPROCESS table by the import processor.
193 int nSubTransId = serviceBroker.getUniqueNo();
194 if ( nSubTransId != -1 )
195 {
196 importDataSubSet.setTransId( nSubTransId );
197 try
198 {
199 tmImport.addSubTransaction(nSubTransId, importDataSubSet );
200 (new AssetServiceManager(sType, importDataSubSet, this)).startManager();
201 }
202 catch ( AssetServiceManagerException rasme )
203 {
204 // Remove the assets from the ASSETS_INPROCESS table and remove this persisted
205 // transaction from TransList.per
206 tmImport.removeSubTransaction( nSubTransId );
207 new FlexError(FlexError.CRITICAL, sThisService, IDENTIFIER, rasme);
208 notifyListener();
209 return new ImportResult(false);
210 }
211 nManagerRunning++;
212 }
213 }
214 }
215
216 // while there are services still running, just wait until be notified of an update;
217 // if all services are done, exit loop and exit Asset Service
218 while (nManagerRunning > 0 )
219 {
220 try
221 {
222 this.wait();
223 if ( subImportDataReturned != null )
224 tmImport.removeSubTransaction( subImportDataReturned.getTransId() );
225 }
226 catch (InterruptedException ie)
227 {
228 // Remove the assets from the ASSETS_INPROCESS table and remove this persisted
229 // transaction from TransList.per
230 tmImport.setTransactionCompletedState();
231 notifyListener();
232 return new ImportResult(false);
233 }
234 }
235
236 // Run Post-Services
237 // Start an instance of the Asset Service Manager in a different thread and waits
238 // for it to finish; if something wrong happens, abort the Import Asset Service
239 /*
240 * NOTE: Postservices are not supported at this moment.
241 *
242 * Before enabling this code we have to make sure that the importData variable
243 * holds all assets as modified by services in roletype_services.config.
244 *
245 if ( importData != null )
246 {
247 try
248 {
249 sServiceType = AssetServiceManager.POSTSERVICES;
250 sNewThreadName = sThreadName + nThreadCounter++;
251 ThreadManager.requestService( new AssetServiceManager(sServiceType, importData), this, null );
252 this.wait();
253 }
254 catch (InterruptedException ie)
255 {
256 // Remove the assets from the ASSETS_INPROCESS table and remove this persisted
257 // transaction from TransList.per
258 tmImport.setTransactionCompletedState();
259 notifyListener();
260 return new ImportResult(false);
261 }
262 catch (AssetServiceManagerException rasme)
263 {
264 // Remove the assets from the ASSETS_INPROCESS table and remove this persisted
265 // transaction from TransList.per
266 tmImport.setTransactionCompletedState();
267 new FlexError(FlexError.CRITICAL, sThisService, IDENTIFIER, rasme);
268 notifyListener();
269 return new ImportResult(false);
270 }
271 }
272 */
273
274 // Remove any asset left in ASSETS_INPROCESS table and remove this persisted
275 // transaction from TransList.per
276 tmImport.setTransactionCompletedState();
277
278 notifyListener();
279 return new ImportResult(bContinue);
280 }
281 finally
282 {
283 // Unlock hot directory
284 if ( bLockHotDir )
285 ImportProcessor.unlockHotDir(sHotDirToLock);
286 }
287 }
288
289 /**
290 * create all subsets of ImportData (one per file type) and return
291 * them in a hashtable.
292 * key = file type; value = ImportData sub set
293 **/
294 private Hashtable createImportDataSubSets()
295 {
296 String[] saType = importData.getTypesFoundRef().getTypes();
297 Hashtable hSubSet = null;
298 if (saType != null && saType.length > 0)
299 {
300 hSubSet = new Hashtable(saType.length);
301
302 for (int i = 0; i < saType.length; i++)
303 {
304 ImportData importDataSubSet = (ImportData) importData.clone();
305 int indexOfPeriod = saType[i].indexOf(".");
306 String sRole;
307 String sType;
308 if ( indexOfPeriod != -1 )
309 {
310 sRole = saType[i].substring( 0, indexOfPeriod );
311 sType = saType[i].substring( indexOfPeriod + 1 );
312 }
313 else
314 {
315 // Log error; saType[i] doesn't contain a valid role.type String.
316 Vector vAssets = importDataSubSet.getDisguiseRecordRef().getAssets( "ALL", saType[i], "PARENT" );
317 if ( vAssets != null && vAssets.size() > 0 )
318 {
319 DisguiseAssetRecordData asset;
320 Vector vBadAssets = new Vector();
321 for ( int k = 0; k < vAssets.size(); k++ )
322 {
323 asset = (DisguiseAssetRecordData) vAssets.elementAt(k);
324 if ( asset.getAssetRoleId() == 0 )
325 vBadAssets.addElement( asset.getServer() + ":/" + asset.getLocation() + asset.getFileName() );
326 }
327 if ( vBadAssets.size() > 0 )
328 {
329 // 6968=%%1 is not a valid role.type. The following assets will not be imported:
330 StringBuffer sbError = new StringBuffer( Resources.get(6968, saType[i]) + "\r\n" );
331 for ( int j = 0; j < vBadAssets.size(); j++ )
332 sbError.append( " " + (String)vBadAssets.elementAt(j) + "\r\n" );
333
334 new FlexError(FlexError.CRITICAL, sThisService, IDENTIFIER, sbError.toString());
335 }
336 }
337 continue;
338 }
339
340 DisguiseRecordData disguiseRecorDataSubSet = importDataSubSet.getDisguiseRecordRef();
341 DisguiseBucketRecordData[] buckets = disguiseRecorDataSubSet.getBuckets();
342 if ( buckets != null )
343 {
344 Vector vBucketsToUse = new Vector();
345 for ( int j = 0; j < buckets.length; j++ )
346 {
347 if ( !(buckets[j].removePrimaryAssetsNotInRoleType( sRole, sType )) )
348 vBucketsToUse.addElement( buckets[j] );
349 }
350 if ( vBucketsToUse.size() > 0 )
351 {
352 DisguiseBucketRecordData[] arrayOfBucketsToUse = new DisguiseBucketRecordData[ vBucketsToUse.size() ];
353 vBucketsToUse.copyInto( arrayOfBucketsToUse );
354 disguiseRecorDataSubSet.setBucket( arrayOfBucketsToUse );
355 hSubSet.put(saType[i], importDataSubSet);
356 }
357 }
358 }
359 }
360 return hSubSet;
361 }
362
363 /**
364 * update the ImportData after the set of services are executed for
365 * a ImportData sub set.
366 **/
367 private synchronized void notify(ImportResult importResult)
368 {
369 if ( importResult == null )
370 {
371 subImportDataReturned = null;
372 bContinue = false;
373 }
374 else if ( importResult.isSuccess() ) // true
375 {
376 subImportDataReturned = importResult.getImportData();
377 bContinue = true;
378 }
379 else // false
380 {
381 subImportDataReturned = importResult.getImportData();
382 bContinue = false;
383 }
384 nManagerRunning--;
385 this.notifyAll();
386 }
387
388 /**
389 * Called when a thread task is about to begin.
390 * @param consumer the instance that this task will run against.
391 * @param obj the user defined parameter for this task.
392 */
393 public void threadTaskStart ( ThreadConsumerI consumer, Object obj ) {}
394
395 /**
396 * Called when a thread task has just finished.
397 * @param consumer the instance that this task will run against.
398 * @param obj the user defined parameter for this task.
399 */
400 public void threadTaskEnd ( ThreadConsumerI consumer, Object obj )
401 {
402 notify( (ImportResult)(((ServiceManager)consumer).getResult()) );
403 }
404
405 private void notifyListener()
406 {
407 // If a listener is up, notify it that this service is done
408 if ( listener != null )
409 {
410 Diagnostic.trace(Diagnostic.APPSERVER_SERVICES, "ImportAssetService done; sending acknowledge to import processor for Id: " + sSubTransId + "!!!");
411 ResultListener.getInstance().serviceDone(sSubTransId);
412 }
413 }
414 }