View Javadoc

1   /*
2    * Copyright 2008 ATG Import Service Project
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *   http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package atg.epub;
18  
19  import java.io.File;
20  import java.io.FileOutputStream;
21  import java.io.FileReader;
22  import java.io.BufferedReader;
23  import java.io.FileWriter;
24  import java.io.IOException;
25  import java.sql.Connection;
26  import java.sql.DriverManager;
27  import java.sql.SQLException;
28  import java.sql.PreparedStatement;
29  import java.sql.ResultSet;
30  import java.util.Iterator;
31  import java.util.List;
32  import java.util.ArrayList;
33  
34  import atg.dtm.TransactionDemarcation;
35  import atg.dtm.TransactionDemarcationException;
36  import atg.epub.project.Process;
37  import atg.epub.project.ProcessHome;
38  import atg.epub.project.ProjectConstants;
39  import atg.nucleus.GenericService;
40  import atg.process.action.ActionConstants;
41  import atg.process.action.ActionException;
42  import atg.repository.MutableRepository;
43  import atg.repository.Repository;
44  import atg.repository.RepositoryException;
45  import atg.repository.RepositoryItem;
46  import atg.security.Persona;
47  import atg.security.ThreadSecurityManager;
48  import atg.security.User;
49  import atg.userdirectory.UserDirectoryUserAuthority;
50  import atg.versionmanager.VersionManager;
51  import atg.versionmanager.WorkingContext;
52  import atg.versionmanager.Workspace;
53  import atg.versionmanager.exceptions.VersionException;
54  import atg.workflow.ActorAccessException;
55  import atg.workflow.MissingWorkflowDescriptionException;
56  import atg.workflow.WorkflowConstants;
57  import atg.workflow.WorkflowException;
58  import atg.workflow.WorkflowManager;
59  import atg.workflow.WorkflowView;
60  
61  import atg.adapter.gsa.xml.ImportItem;
62  import atg.adapter.gsa.xml.ImportFailedItem;
63  import atg.adapter.gsa.xml.ImportFileParser;
64  import atg.adapter.gsa.xml.ReferenceItemGenerator;
65  import atg.adapter.gsa.xml.ImportWorkerThread;
66  import atg.adapter.util.RepositoryUtils;
67  
68  import javax.ejb.CreateException;
69  import javax.servlet.ServletContext;
70  import javax.transaction.TransactionManager;
71  
72  /***
73   * This class provides an import service, which enables customers to import their data into a versioned repository.
74   * 
75   * The service works on a single xml file and imports its contents into the versioned repository.
76   * 
77   * You may choose between the early and late workflows. /Content Administration/import-late.wdl for late and
78   * /Content Administration/import-early.wdl for early.
79   * 
80   * @author Patrick Mc Erlean
81   * @version $Id: //user/pmcerlean/main/Import/src/classes/atg/epub/ImportService.java#2 $
82   */
83  public class ImportService extends GenericService
84  {
85    //-------------------------------------
86    public static String CLASS_VERSION = "$Id: //user/pmcerlean/main/Import/src/classes/atg/epub/ImportService.java#2 $$Change: 490318 $";
87  
88    //-------------------------------------
89    public static final String M_SERVICE_STATUS_WAITING_TO_START = "Service: Waiting to start";
90    public static final String M_SERVICE_STATUS_PROJECT_CREATION = "Project : Creating";
91    public static final String M_SERVICE_STATUS_PRE_DATA_IMPORT = "Data Import : Preparing";
92    public static final String M_SERVICE_STATUS_DATA_IMPORT_BATCH_CREATION = "Data Import : Creating the batches";
93    public static final String M_SERVICE_STATUS_DATA_IMPORT_ADD_UPDATE_PHASE = "Data Import : Add Update phase";
94    public static final String M_SERVICE_STATUS_DATA_IMPORT_REFERENCE_UPDATE_PHASE = "Data Import : Reference Update phase";
95    public static final String M_SERVICE_STATUS_DATA_IMPORT_DELETE_PHASE = "Data Import : Delete phase";
96    public static final String M_SERVICE_STATUS_DATA_IMPORT_PROCESSING_FAILED_DELETIONS = "Data Import : Processing failed deletions";
97    public static final String M_SERVICE_STATUS_PROJECT_ADVANCE_WORKFLOW = "Project : Advance workflow";
98    public static final String M_SERVICE_STATUS_COMPLETED_SUCCESSFULLY = "Service : Completed successfully";
99    public static final String M_SERVICE_STATUS_COMPLETED_WITH_ERRORS = "Service : Completed successfully (Check error file)";
100   public static final String M_SERVICE_STATUS_CANCELLED = "Service : Import cancelled";
101   public static final String M_SERVICE_STATUS_FATAL_ERROR_THRESHOLD_REACHED = "Service : Fatal Error : Import error threshold reached";
102   public static final String M_SERVICE_STATUS_FATAL_ERROR_THREAD_DIED = "Service : Fatal Error : ";
103   public static final String M_SERVICE_STATUS_FATAL_ERROR_IO = "Service : Fatal Error : IO Problem";
104   public static final String M_SERVICE_STATUS_FATAL_ERROR_DATABASE = "Service : Fatal Error : Database problem";
105   public static final String M_SERVICE_STATUS_FATAL_ERROR_THREADS = "Service : Fatal Error : Threading problem";
106 
107   public static final int PHASE_ADD_UPDATE = 0;
108   public static final int PHASE_REFERENCE_UPDATE = 1;
109   public static final int PHASE_DELETE = 2;
110   
111   public static final String M_SEGMENT_FILE_STUB = "IMPORT_SEGMENT_";
112   public static final String M_SEGMENT_FILE_EXTENSION = ".xml";
113   public static final String M_FAILURES_FILENAME = "IMPORT_FAILURES.log";
114   
115   public static final String M_TAG_ADD_ITEM_START = "<add-item";
116   public static final String M_TAG_ADD_ITEM_END = "</add-item";
117   public static final String M_TAG_UPDATE_ITEM_START = "<update-item";
118   public static final String M_TAG_UPDATE_ITEM_END = "</update-item";
119   public static final String M_TAG_REMOVE_ITEM_START = "<remove-item";
120   public static final String M_TAG_REMOVE_ITEM_END = "</remove-item";
121 
122   public static final String M_ITEM_CATALOG = "catalog";
123   public static final String M_ITEM_CATEGORY = "category";
124   public static final String M_ITEM_PRODUCT = "product";
125   public static final String M_ITEM_SKU = "sku";
126   public static final String M_ITEM_MEDIA_EXTERNAL = "media-external";
127   public static final String M_ITEM_FOLDER = "folder";
128 
129   public static final int THREAD_STATUS_STARTED = 0;
130   public static final int THREAD_STATUS_NOTIFIED = 1;
131   public static final int THREAD_STATUS_PROCESSING = 2;
132   public static final int THREAD_STATUS_PHASE_COMPLETED = 3;
133   
134   //-------------------------------------
135   // property: transactionManager
136   //-------------------------------------
137   private TransactionManager mTransactionManager = null;
138     
139   /***
140    * @return Returns the transactionManager.
141    */
142   public TransactionManager getTransactionManager()
143   {
144     return mTransactionManager;
145   }
146 
147   /***
148    * @param pTransactionManager The transactionManager to set.
149    */
150   public void setTransactionManager (TransactionManager pTransactionManager)
151   {
152     mTransactionManager = pTransactionManager;
153   }
154 
155   //-------------------------------------
156   // property: versionManager
157   //-------------------------------------
158   private VersionManager mVersionManager = null;
159       
160   /***
161    * @return Returns the versionManager.
162    */
163   public VersionManager getVersionManager()
164   {
165     return mVersionManager;
166   }
167 
168   /***
169    * @param pVersionManager The versionManager to set.
170    */
171   public void setVersionManager (VersionManager pVersionManager)
172   {
173     mVersionManager = pVersionManager;
174   }
175 
176   //-------------------------------------
177   // property: workflowManager
178   //-------------------------------------
179   private WorkflowManager mWorkflowManager = null;
180       
181   /***
182    * @return Returns the workflowManager.
183    */
184   public WorkflowManager getWorkflowManager()
185   {
186     return mWorkflowManager;
187   }
188 
189   /***
190    * @param pWorkflowManager The workflowManager to set.
191    */
192   public void setWorkflowManager (WorkflowManager pWorkflowManager)
193   {
194     mWorkflowManager = pWorkflowManager;
195   }
196 
197   //-------------------------------------
198   // property: userAuthority
199   //-------------------------------------
200   private UserDirectoryUserAuthority mUserAuthority = null;
201 
202   /***
203    * Returns the UserAuthority
204    */
205   public UserDirectoryUserAuthority getUserAuthority()
206   {
207     return mUserAuthority;
208   }
209 
210   /***
211    * Sets the UserAuthority
212    */
213   public void setUserAuthority (UserDirectoryUserAuthority pUserAuthority)
214   {
215     mUserAuthority = pUserAuthority;
216   }
217 
218   //-------------------------------------
219   // property: personaPrefix
220   //-------------------------------------
221   private String mPersonaPrefix = "Profile$login$";
222 
223   /***
224    * Returns the PersonaPrefix which is supplied for login
225    */
226   public String getPersonaPrefix()
227   {
228     return mPersonaPrefix;
229   }
230 
231   /***
232    * Sets the PersonaPrefix
233    */
234   public void setPersonaPrefix(String pPersonaPrefix)
235   {
236     mPersonaPrefix = pPersonaPrefix;
237   }
238 
239   //---------------------------------------------
240   // property: userName (defaults to publishing)
241   //---------------------------------------------
242   private String mUserName = "publishing";
243 
244   /***
245    * Returns the UserName which is supplied upon check-in and for logging in.
246    */
247   public String getUserName()
248   {
249     return mUserName;
250   }
251 
252   /***
253    * Sets the UserName
254    */
255   public void setUserName (String pUserName)
256   {
257     mUserName = pUserName;
258   }
259 
260   //--------------------------------------------
261   // property: workflowName (defaults to early)
262   //--------------------------------------------
263   private String mWorkflowName = "/Content Administration/import-early.wdl";
264   
265   /***
266    * Returns the workflowName property
267    */
268   public String getWorkflowName()
269   {
270     return mWorkflowName;
271   }
272 
273   /***
274    * Sets the workflowName property
275    */
276   public void setWorkflowName (String string)
277   {
278     mWorkflowName = string;
279   } 
280 
281   //---------------------------------------------
282   // property: taskOutcomeId (defaults to 4.1.1)
283   //---------------------------------------------
284   private String mTaskOutcomeId = "4.1.1";
285 
286   /***
287    * @return Returns the taskOutcomeId.
288    */
289   public String getTaskOutcomeId ()
290   {
291     return mTaskOutcomeId;
292   }
293 
294   /***
295    * @param pTaskOutcomeId The taskOutcomeId to set.
296    */
297   public void setTaskOutcomeId (String pTaskOutcomeId)
298   {
299     mTaskOutcomeId = pTaskOutcomeId;
300   }
301 
302   //-------------------------------------------------------------------
303   // property: projectName (defaults to Content Administration Import)
304   //--------------------------------------------------------------------
305   private String mProjectName = "Content Administration Import"; 
306     
307   /***
308    * @return Returns the projectName.
309    */
310   public String getProjectName()
311   {
312     return mProjectName;
313   }
314 
315   /***
316    * @param pProjectName The projectName to set.
317    */
318   public void setProjectName (String pProjectName)
319   {
320     mProjectName = pProjectName;
321   }
322 
323   //-------------------------------------------------------------------
324   // property: itemBatchSize (defaults to 1000)
325   //--------------------------------------------------------------------
326   private int mItemBatchSize = 1000; 
327     
328   /***
329    * @return Returns the itemBatchSize.
330    */
331   public int getItemBatchSize()
332   {
333     return mItemBatchSize;
334   }
335 
336   /***
337    * @param pItemBatchSize The itemBatchSize to set.
338    */
339   public void setItemBatchSize (int pItemBatchSize)
340   {
341     mItemBatchSize = pItemBatchSize;
342   }
343 
344   //-------------------------------------------------------------------
345   // property: maxImportThreads (defaults to 20)
346   //--------------------------------------------------------------------
347   private int mMaxImportThreads = 20; 
348     
349   /***
350    * @return Returns the maxImportThreads.
351    */
352   public int getMaxImportThreads()
353   {
354     return mMaxImportThreads;
355   }
356 
357   /***
358    * @param pMaxImportThreads The maxImportThreads to set.
359    */
360   public void setMaxImportThreads (int pMaxImportThreads)
361   {
362     mMaxImportThreads = pMaxImportThreads;
363   }
364 
365   //-----------------------------
366   // property: importFilename
367   //-----------------------------
368   private String mImportFilename; 
369     
370   /***
371    * @return Returns the importFilename.
372    */
373   public String getImportFilename()
374   {
375     return mImportFilename;
376   }
377 
378   /***
379    * @param pMaxImportThreads The maxImportThreads to set.
380    */
381   public void setImportFilename (String pImportFilename)
382   {
383     mImportFilename = pImportFilename;
384   }
385 
386   //-----------------------------
387   // property: targetRepository
388   //-----------------------------
389   private Repository mTargetRepository; 
390     
391   /***
392    * @return Returns the targetRepository.
393    */
394   public Repository getTargetRepository()
395   {
396     return mTargetRepository;
397   }
398 
399   /***
400    * @param pTargetRepository The targetRepository to set.
401    */
402   public void setTargetRepository (Repository pTargetRepository)
403   {
404     mTargetRepository = pTargetRepository;
405   }
406 
407   //-----------------------------
408   // property: errorThresholdPerBatch
409   //-----------------------------
410   private int mErrorThresholdPerBatch = 10; 
411     
412   /***
413    * @return Returns the errorThresholdPerBatch.
414    */
415   public int getErrorThresholdPerBatch()
416   {
417     return mErrorThresholdPerBatch;
418   }
419 
420   /***
421    * @param pErrorThresholdPerBatch The percentage error threshold per batch to set.
422    */
423   public void setErrorThresholdPerBatch (int pErrorThresholdPerBatch)
424   {
425     mErrorThresholdPerBatch = pErrorThresholdPerBatch;
426   }
427 
428   //-----------------------------
429   // property: errorThresholdPerImport
430   //-----------------------------
431   private int mErrorThresholdPerImport = 10; 
432     
433   /***
434    * @return Returns the errorThresholdPerImport.
435    */
436   public int getErrorThresholdPerImport()
437   {
438     return mErrorThresholdPerImport;
439   }
440 
441   /***
442    * @param pErrorThresholdPerImport The percentage error threshold per import to set.
443    */
444   public void setErrorThresholdPerImport (int pErrorThresholdPerImport)
445   {
446     mErrorThresholdPerImport = pErrorThresholdPerImport;
447   }
448 
449   //-----------------------------
450   // property: threadMonitorInterval
451   //-----------------------------
452 
453   private long mThreadMonitorInterval;
454   
455   public long getThreadMonitorInterval ()
456   {
457     return mThreadMonitorInterval;
458   }
459 
460   public void setThreadMonitorInterval (long pThreadMonitorInterval)
461   {
462     mThreadMonitorInterval = pThreadMonitorInterval;
463   }
464 
465   //-----------------------------
466   // property: databaseDriver
467   //-----------------------------
468 
469   private String mDatabaseDriver;
470   
471   public String getDatabaseDriver ()
472   {
473     return mDatabaseDriver;
474   }
475 
476   public void setDatabaseDriver (String pDatabaseDriver)
477   {
478     mDatabaseDriver = pDatabaseDriver;
479   }
480 
481   //-----------------------------
482   // property: databaseUrl
483   //-----------------------------
484 
485   private String mDatabaseUrl;
486   
487   public String getDatabaseUrl ()
488   {
489     return mDatabaseUrl;
490   }
491 
492   public void setDatabaseUrl (String pDatabaseUrl)
493   {
494     mDatabaseUrl = pDatabaseUrl;
495   }
496 
497   //-----------------------------
498   // property: databaseUsername
499   //-----------------------------
500 
501   private String mDatabaseUsername;
502   
503   public String getDatabaseUsername ()
504   {
505     return mDatabaseUsername;
506   }
507 
508   public void setDatabaseUsername (String pDatabaseUsername)
509   {
510     mDatabaseUsername = pDatabaseUsername;
511   }
512 
513   //-----------------------------
514   // property: databasePassword
515   //-----------------------------
516 
517   private String mDatabasePassword;
518   
519   public String getDatabasePassword ()
520   {
521     return mDatabasePassword;
522   }
523 
524   public void setDatabasePassword (String pDatabasePassword)
525   {
526     mDatabasePassword = pDatabasePassword;
527   }
528 
529   //-----------------------------
530   // Internal member data.
531   //-----------------------------
532 
533   private Connection mDatabaseConnection = null;
534 
535   private String mServiceStatus = M_SERVICE_STATUS_WAITING_TO_START;
536   
537   public String getServiceStatus ()
538   {
539     return mServiceStatus;
540   }
541 
542   private String mImportDirectory;
543   
544   /***
545    * @return Returns the importDirectory.
546    */
547   public String getImportDirectory()
548   {
549     return mImportDirectory;
550   }
551 
552   public void setImportDirectory(String pImportDirectory)
553   {
554     mImportDirectory = pImportDirectory;
555   }
556 
557   private Workspace mWorkspace;
558 
559   public Workspace getWorkspace()
560   {
561     return mWorkspace;
562   }
563 
564   private ReferenceItemGenerator mReferenceItemGenerator;  
565   
566   /***
567    * @return Returns the importReferenceGenerator.
568    */
569   public ReferenceItemGenerator getReferenceItemGenerator()
570   {
571     return mReferenceItemGenerator;
572   }
573   
574   public boolean getCancelCommandReceived()
575   {
576     return mCancelCommandReceived;
577   }
578   
579   private boolean mCancelCommandReceived = false;
580   
581   private ArrayList mFailedDeletions = new ArrayList();
582 
583   /***
584    * @return Returns the failedDeletions.
585    */
586   public ArrayList getFailedDeletions()
587   {
588     return mFailedDeletions;
589   }
590 
591   private boolean mDataImportErrors = false;
592 
593   /***
594    * @return Returns the failedDeletions.
595    */
596   public void setDataImportErrors()
597   {
598     mDataImportErrors = true;
599   }
600 
601   private int mSegmentCount = 0;
602   private User mNewUser;
603   private ImportWorkerThread[] mImportWorkerThreads = null;
604   private int[] mImportWorkerThreadsStatus = null;
605   private Process mProcess;
606   private int mTotalAssets = 0;
607   private long mAssetsPerSecondExcludingCheckin;
608   private long mAssetsPerSecondIncludingCheckin;
609   private long mTotalTime;
610   private FileWriter mFailedItemsFileWriter;
611   private int mFailedBatches = 0;
612   private boolean mErrorThresholdReached = false;
613   private ArrayList mIndexNames;
614 
615   //-------------------------------------
616   // Constructor
617   //-------------------------------------
618   public ImportService()
619   {    
620   }
621   
622   //-------------------------------------
623   /***
624    * This is the main execution method for the service. This method sets the security
625    * context on the thread for the user specified in the userName property. Next, it creates a project
626    * and then calls importData(). Next, it attempts to advance the project's workflow. Finally, it
627    * unsets the security context.
628    */
629   
630   public boolean executeImport()
631   throws Exception
632   {
633     String workspaceName;
634     ProcessHome processHome;
635     String projectName;
636     TransactionDemarcation transactionDemarcation = new TransactionDemarcation(); 
637     boolean rollback = true;
638     int indexOfLastSeparator;
639     ImportTimer checkinTimer;
640     boolean importSuccess = true;
641 
642     System.out.println ("********* ENTER *****************");
643     
644     // Initialisation
645     
646     mSegmentCount = 0;
647     mNewUser = null;
648     mImportWorkerThreads = null;
649     mImportWorkerThreadsStatus = null;
650     mProcess = null;
651     mTotalAssets = 0;
652     mAssetsPerSecondExcludingCheckin = 0;
653     mAssetsPerSecondIncludingCheckin = 0;
654     mTotalTime = 0;
655     mFailedItemsFileWriter = null;
656     mFailedBatches = 0;
657     mErrorThresholdReached = false;
658     mCancelCommandReceived = false;
659     
660     // Set the service status
661     
662     mServiceStatus = M_SERVICE_STATUS_PROJECT_CREATION;
663     
664     // Create the project for the import.
665     
666     try
667     {
668       transactionDemarcation.begin (getTransactionManager());
669       
670       assumeUserIdentity();
671       
672       projectName = getProjectName();
673                          
674       processHome = ProjectConstants.getPersistentHomes().getProcessHome();
675 
676       mProcess = processHome.createProcessForImport (projectName, getWorkflowName(), false);
677       
678       workspaceName = mProcess.getProject().getWorkspace();
679 
680       mWorkspace = getVersionManager().getWorkspaceByName(workspaceName);
681       
682       WorkingContext.pushDevelopmentLine (mWorkspace);
683 
684       System.out.println ("SERVICE: Import Project Created. Id: " + mProcess.getProject().getId() + " Name: " + mProcess.getProject().getDisplayName());
685       rollback = false;
686     }
687     catch(VersionException e)
688     {
689       throw e;
690     }
691     catch (TransactionDemarcationException e)
692     {
693       throw e;
694     }
695     catch (CreateException e)
696     {
697       throw e;
698     }
699     catch (WorkflowException e)
700     {
701       throw e;
702     }
703     catch (ActionException e)
704     {
705       throw e;
706     }
707     catch (Exception e)
708     {
709       throw e;
710     }
711     finally
712     {
713       try 
714       {
715         transactionDemarcation.end(rollback);
716       }
717       catch (TransactionDemarcationException tde)
718       {
719         throw tde;
720       }
721     }
722     
723     // Check for cancel
724     
725     if (mCancelCommandReceived)
726     {
727       System.out.println ("SERVICE: Import cancellation request received prior to data import. Delete the project and complete");
728       deleteProject ();
729       mServiceStatus = M_SERVICE_STATUS_CANCELLED;
730       return (false);
731     }
732 
733     // Set the service status
734 
735     mServiceStatus = M_SERVICE_STATUS_PRE_DATA_IMPORT;
736 
737     // Find the import file directory.
738     
739     indexOfLastSeparator = getImportFilename().lastIndexOf(File.separator);
740     
741     if (indexOfLastSeparator == -1)
742     {
743       mImportDirectory = "";
744     }
745     else
746     {
747       mImportDirectory = getImportFilename().substring (0, indexOfLastSeparator);
748     }
749     
750     // Create the log file for failed items.
751     
752     if (createFailedItemLogFile () == false)
753     {
754       System.out.println ("SERVICE: Item log file creation failed. Delete the project and complete");
755       deleteProject ();
756       mServiceStatus = M_SERVICE_STATUS_FATAL_ERROR_IO;
757       return (false);
758     }
759         
760     // Create and set up the reference item generator.
761     
762     if (createReferenceItemGenerator ())
763     {
764       // Import the data.
765       
766       if (mCancelCommandReceived)
767       {
768         System.out.println ("SERVICE: Import cancellation request received prior to data import (but after temporary reference generation). Delete the project and complete");
769         deleteProject ();
770         mServiceStatus = M_SERVICE_STATUS_CANCELLED;
771         return (false);
772       }
773       
774       // Disable the indexes
775       
776       System.out.println ("SERVICE: Disabling the indexes");
777 
778       if (disableIndexes () == false)
779       {
780         System.out.println ("SERVICE: Data import was unsuccessful. Unable to disable the indexes");
781         deleteProject ();
782         return (false);
783       }
784       
785       // Disable the indexes
786       
787       importSuccess = importData ();
788       
789       // Rebuild the indexes
790       
791       System.out.println ("SERVICE: Rebuilding the indexes");
792 
793       if (rebuildIndexes () == false)
794       {
795         System.out.println ("SERVICE: Unable to rebuild the indexes");
796         //deleteProject ();
797         //return;
798       }
799       
800       if (!importSuccess)
801       {
802         // Data import unsuccessful.
803         
804         System.out.println ("SERVICE: Data import was unsuccessful. Delete the project and complete");
805         deleteProject ();
806         return (false);
807       }
808     }
809     else
810     {
811       System.out.println ("SERVICE: failed to create the temporary reference items. Delete the project and complete");
812       deleteProject ();
813       mServiceStatus = M_SERVICE_STATUS_FATAL_ERROR_DATABASE;
814       return (false);
815     }
816 
817     mServiceStatus = M_SERVICE_STATUS_PROJECT_ADVANCE_WORKFLOW;
818 
819     // Advance the workflow after the data import.
820     
821     System.out.println ("SERVICE: Data import complete. Check-in the project");
822 
823     transactionDemarcation = new TransactionDemarcation(); 
824     rollback = true;
825 
826     try
827     {
828       transactionDemarcation.begin (getTransactionManager());
829       
830       checkinTimer = new ImportTimer ("CHECKIN TIME");
831       checkinTimer.start ();
832       
833       advanceWorkflow (mProcess);
834       
835       checkinTimer.stop ();
836       checkinTimer.display ();
837       
838       mTotalTime += checkinTimer.getTime();
839       
840       mAssetsPerSecondIncludingCheckin = mTotalAssets / (mTotalTime / 1000);
841       
842       System.out.println ("SERVICE: ASSETS: " + mTotalAssets +
843                            " ASSETS PER SECOND (Including Check In): " + mAssetsPerSecondIncludingCheckin);
844       rollback = false;
845     }
846     catch (TransactionDemarcationException e)
847     {
848       throw e;
849     }
850     catch (WorkflowException e)
851     {
852       throw e;
853     }
854     catch (ActionException e)
855     {
856       throw e;
857     }
858     catch (Exception e)
859     {
860       throw e;
861     }
862     finally
863     {
864       WorkingContext.popDevelopmentLine();
865       releaseUserIdentity();
866       try 
867       {
868         transactionDemarcation.end(rollback);
869       }
870       catch (TransactionDemarcationException tde)
871       {
872         throw tde;
873       }
874     }
875     
876     if (mDataImportErrors)
877     {
878       mServiceStatus = M_SERVICE_STATUS_COMPLETED_WITH_ERRORS;
879     }
880     else
881     {
882       mServiceStatus = M_SERVICE_STATUS_COMPLETED_SUCCESSFULLY;
883     }
884       
885     return (true);
886   }
887   
888   //-------------------------------------
889   /***
890    * This method cancels the import.
891    */
892   public void cancelImport ()
893   {
894     synchronized (this)
895     {
896       mCancelCommandReceived = true;
897     }
898     
899     return;
900   }
901   
902   //-------------------------------------
903   /***
904    * This method advances the workflow to the next state. If using an unaltered copy of the import-late
905    * or import-early workflows, then the taskOutcomeId property should not need to be changed
906    * (default is '4.1.1'). If you are using a different workflow or an altered version of the import-xxxx
907    * workflows, then the taskOutcomeId can be found in the wdl file for the respective workflow.
908    * 
909    * @param pProcess the atg.epub.project.Process object (the project)
910    */
911   private void advanceWorkflow
912   (
913     Process pProcess
914   ) throws WorkflowException, ActionException
915   {
916     RepositoryItem processWorkflow = pProcess.getProject().getWorkflow();
917     String workflowProcessName = processWorkflow.getPropertyValue("processName").toString();
918     String subjectId = pProcess.getId();
919     
920     try
921     {
922       // An alternative would be to use the global workflow view at 
923     
924       WorkflowView wv = getWorkflowManager().getWorkflowView (ThreadSecurityManager.currentUser());
925     
926       wv.fireTaskOutcome (workflowProcessName, WorkflowConstants.DEFAULT_WORKFLOW_SEGMENT,
927                           subjectId,
928                           getTaskOutcomeId(),
929                           ActionConstants.ERROR_RESPONSE_DEFAULT);
930     }
931     catch (MissingWorkflowDescriptionException e)
932     {
933       System.out.println ("SERVICE: Advance Workflow Failed: MissingWorkflowDescriptionException: " + e.getMessage());
934       throw e;
935     }
936     catch (ActorAccessException e)
937     {
938       System.out.println ("SERVICE: Advance Workflow Failed: ActorAccessException: " + e.getMessage());
939       throw e;
940     }
941     catch (ActionException e)
942     {
943       System.out.println ("SERVICE: Advance Workflow Failed: ActionException: " + e.getMessage());
944       throw e;
945     }
946     catch (UnsupportedOperationException e)
947     {
948       System.out.println ("SERVICE: Advance Workflow Failed: UnsupportedOperationException: " + e.getMessage());
949       throw e;
950     }
951   }
952 
953   //-------------------------------------
954   /***
955    * This method sets the security context for the current thread so that the code executes correctly
956    * against secure resources.
957    * 
958    * @return true if the identity was assumed, false otherwise
959    */
960   protected boolean assumeUserIdentity()
961   {
962     if (getUserAuthority () == null)
963     {
964       return false;
965     }
966 
967     mNewUser = new User();
968     
969     Persona persona = (Persona) getUserAuthority().getPersona(getPersonaPrefix() + getUserName());
970     
971     if (persona == null)
972     {
973       return false;
974     }
975 
976     // Create a temporary User object for the identity
977     
978     mNewUser.addPersona(persona);
979 
980     // Replace the current User object
981     
982     ThreadSecurityManager.setThreadUser (mNewUser);
983 
984     return true;
985   }
986 
987   //-------------------------------------
988   /***
989    * This method unsets the security context on the current thread.
990    */
991   protected void releaseUserIdentity ()
992   {
993     ThreadSecurityManager.setThreadUser (null);
994   }
995   
996   //-------------------------------------
997   /***
998    * This method runs a multi-threaded data import.
999    */
1000   private boolean importData ()
1001   {
1002     // Check that the import file exists. If not we're done.
1003     
1004     int numberOfThreads = 0;
1005 
1006     ImportTimer totalTimer = new ImportTimer ("TOTAL TIME");
1007     ImportTimer addUpdatePhaseTimer = new ImportTimer ("Add - Update Phase Time");
1008     ImportTimer referenceUpdatePhaseTimer = new ImportTimer ("Reference - Update Phase Time");
1009     ImportTimer deletePhaseTimer = new ImportTimer ("Delete Phase Time");
1010 
1011     mServiceStatus = M_SERVICE_STATUS_DATA_IMPORT_BATCH_CREATION;
1012     // Split the file up into segments containing mItemBatchSize items.
1013     // The segments are stored in individual temporary files.
1014     
1015     mSegmentCount = segmentImportFile ();
1016     
1017     if (mSegmentCount == 0)
1018     {
1019       System.out.println ("SERVICE: There are no segments");
1020       mServiceStatus = M_SERVICE_STATUS_FATAL_ERROR_IO;
1021       return (false);
1022     }
1023     
1024     // Check for cancellation.
1025     
1026     if (mCancelCommandReceived)
1027     {
1028       System.out.println ("SERVICE: Import cancellation request received prior worker thread creation. Return data import failure");
1029       mServiceStatus = M_SERVICE_STATUS_CANCELLED;
1030       return (false);
1031     }
1032 
1033     mServiceStatus = M_SERVICE_STATUS_DATA_IMPORT_ADD_UPDATE_PHASE;
1034     
1035     // Start up N threads and pass a list of files to each. N cannot exceed the value of mMaxImportThreads.
1036     // These threads will initialised to the ADD / UPDATE phase. They wait until they are told to process a phase.
1037     
1038     numberOfThreads = initiateImportWorkerThreads (mSegmentCount);
1039     
1040     if (mCancelCommandReceived)
1041     {
1042       mServiceStatus = M_SERVICE_STATUS_FATAL_ERROR_THREADS;
1043       return (false);
1044     }
1045 
1046 
1047     System.out.println ("SERVICE: Sleeping for " + (numberOfThreads + 1) + " seconds to allow all threads to get started");
1048     
1049     try
1050     {
1051       Thread.sleep (1000 * (numberOfThreads + 1));
1052     }
1053     catch (InterruptedException e)
1054     {
1055     }
1056 
1057     // Start the Add / Update phase.
1058     
1059     totalTimer.start();
1060     
1061     System.out.println ("SERVICE: ****** ADD / UPDATE phase");
1062 
1063     addUpdatePhaseTimer.start();
1064     
1065     startPhase (PHASE_ADD_UPDATE);
1066     
1067     // Wait on each of them to complete the Add / Update phase.
1068     
1069     if (waitForPhaseCompletion () == false)
1070     {
1071       terminateImportWorkerThreads ();
1072       return (false);
1073     }
1074     
1075     addUpdatePhaseTimer.stop();
1076     addUpdatePhaseTimer.display();
1077 
1078     // Persist any references that have been generated (by non primary property references)
1079     
1080     try
1081     {
1082       mReferenceItemGenerator.persistReferenceItemList ();
1083     }
1084     catch (IOException e)
1085     {
1086       System.out.println ("SERVICE: IOException: " + e.getMessage());
1087     }
1088     
1089     // Start the Reference Update phase.
1090 
1091     mServiceStatus = M_SERVICE_STATUS_DATA_IMPORT_REFERENCE_UPDATE_PHASE;
1092 
1093     System.out.println ("SERVICE: ****** REFERENCE UPDATE phase");
1094 
1095     referenceUpdatePhaseTimer.start();
1096 
1097     startPhase (PHASE_REFERENCE_UPDATE);
1098     
1099     // Wait on each of them to complete the Reference Update phase.
1100     
1101     if (waitForPhaseCompletion () == false)
1102     {
1103       System.out.println ("SERVICE: REFERENCE / UPDATE phase terminated. Terminate any running worker threads and return data import failure");
1104       terminateImportWorkerThreads ();
1105       return (false);
1106     }
1107     
1108     referenceUpdatePhaseTimer.stop();
1109     referenceUpdatePhaseTimer.display();
1110 
1111     // Start the Delete phase.
1112     
1113     System.out.println ("SERVICE: ****** DELETE phase");
1114 
1115     mServiceStatus = M_SERVICE_STATUS_DATA_IMPORT_DELETE_PHASE;
1116 
1117     deletePhaseTimer.start();
1118 
1119     startPhase (PHASE_DELETE);
1120     
1121     // Wait on each of them to complete the delete phase.
1122     
1123     if (waitForPhaseCompletion () == false)
1124     {
1125       System.out.println ("SERVICE: DELETE phase terminated. Terminate any running worker threads and return data import failure");
1126       terminateImportWorkerThreads ();
1127       return (false);
1128     }
1129     
1130     deletePhaseTimer.stop();
1131     deletePhaseTimer.display();
1132 
1133     // Terminate the import worker threads.
1134     
1135     terminateImportWorkerThreads ();
1136     
1137     if (mCancelCommandReceived)
1138     {
1139       System.out.println ("SERVICE: Import cancellation request received prior to processing failed deletions. Return data import failure");
1140       mServiceStatus = M_SERVICE_STATUS_CANCELLED;
1141       return (false);
1142     }
1143     
1144     mServiceStatus = M_SERVICE_STATUS_DATA_IMPORT_PROCESSING_FAILED_DELETIONS;
1145     
1146     processFailedDeletions ();
1147     
1148     // Remove the dummy reference items.
1149     
1150     mReferenceItemGenerator.deleteAllDummyReferenceItems ();
1151     
1152     totalTimer.stop();
1153     totalTimer.display();
1154     
1155     // Calculate assets per second
1156     
1157     mTotalTime += totalTimer.getTime();
1158     
1159     mAssetsPerSecondExcludingCheckin = mTotalAssets / (totalTimer.getTime() / 1000);
1160     
1161     System.out.println ("SERVICE: ASSETS: " + mTotalAssets +
1162                          " ASSETS PER SECOND (Excluding Check In): " + mAssetsPerSecondExcludingCheckin);
1163 
1164     if (mCancelCommandReceived)
1165     {
1166       System.out.println ("SERVICE: Import cancellation request received during failed deletion processing. Return data import failure");
1167       return (false);
1168     }
1169     else
1170     {
1171       return (true);
1172     }
1173   }
1174  
1175   //-------------------------------------
1176   /***
1177    * This method creates and starts the appropriate number of import worker threads.
1178    */
1179   private int initiateImportWorkerThreads (int pSegmentCount)
1180   {
1181     int numberOfThreads = 0;
1182     int segmentsPerThread = 0;
1183     int startSegment = 1;
1184     int endSegment = 1;
1185     int extras = 0;
1186 
1187     // Work out how many threads that need to be started and how many segments each will get.
1188     
1189     if (pSegmentCount > getMaxImportThreads())
1190     {
1191       numberOfThreads = getMaxImportThreads();
1192       segmentsPerThread = pSegmentCount / numberOfThreads;
1193       extras = pSegmentCount % numberOfThreads;
1194     }
1195     else
1196     {
1197       numberOfThreads = pSegmentCount;
1198       segmentsPerThread = 1;
1199       extras = 0;
1200     }
1201     
1202     mImportWorkerThreads = new ImportWorkerThread[numberOfThreads];
1203     mImportWorkerThreadsStatus = new int[numberOfThreads];
1204     
1205     // Create the threads.
1206     
1207     for (int index = 0; index < numberOfThreads; index++)
1208     {
1209       if (extras > 0)
1210       {
1211         endSegment = startSegment + segmentsPerThread;
1212         extras--;
1213       }
1214       else
1215       {
1216         endSegment = startSegment + segmentsPerThread - 1;
1217       }
1218       
1219       // Start the thread
1220       
1221       mImportWorkerThreads[index] = new ImportWorkerThread (index, this, startSegment, endSegment);
1222       mImportWorkerThreadsStatus[index] = THREAD_STATUS_STARTED;
1223       mImportWorkerThreads[index].start ();      
1224       
1225       // Increase the start count
1226       
1227       startSegment = endSegment + 1;      
1228     }
1229     
1230     return (numberOfThreads);
1231   }
1232 
1233   //-------------------------------------
1234   /***
1235    * This method starts the import for the specified phase.
1236    */
1237   private void startPhase (int pPhase)
1238   {
1239     mFailedBatches = 0;
1240     
1241     for (int index = 0; index < mImportWorkerThreads.length; index++)
1242     {
1243       // Set the threads phase.
1244       
1245       mImportWorkerThreads[index].setPhase (pPhase);
1246       
1247       // Notify the thread to begin processing.
1248       
1249       synchronized (mImportWorkerThreads[index])
1250       {
1251         mImportWorkerThreadsStatus[index] = THREAD_STATUS_NOTIFIED;
1252         mImportWorkerThreads[index].notify ();
1253       }
1254     }
1255     
1256     return;
1257   }
1258 
1259   //-------------------------------------
1260   /***
1261    * This method waits for the specified phase to complete.
1262    */
1263   private boolean waitForPhaseCompletion ()
1264   {
1265     int activeThreads;
1266 
1267     while (true)
1268     {
1269       // Check for cancel.
1270       
1271       
1272       // Check the status of each thread.
1273       
1274       activeThreads = 0;
1275     
1276       for (int index = 0; index < mImportWorkerThreads.length; index++)
1277       {
1278         if (mImportWorkerThreads[index].isAlive() == false)
1279         {
1280           // Thread has died. There has either been an error or a cancellation request has been received.
1281 
1282           if (getCancelCommandReceived())
1283           {
1284             if (mErrorThresholdReached)
1285             {
1286               mServiceStatus = M_SERVICE_STATUS_FATAL_ERROR_THRESHOLD_REACHED;
1287             }
1288             else
1289             {
1290               mServiceStatus = M_SERVICE_STATUS_CANCELLED;
1291             }
1292           }
1293           else
1294           {
1295             mServiceStatus = M_SERVICE_STATUS_FATAL_ERROR_THREADS;
1296           }
1297 
1298           return (false);
1299         }
1300         
1301         if (mImportWorkerThreadsStatus[index] != THREAD_STATUS_PHASE_COMPLETED)
1302         {
1303           // Add one to active threads.
1304           
1305           activeThreads++;
1306         }
1307       }
1308       
1309       // Check if there are any active threads.
1310       
1311       if (activeThreads == 0)
1312       {
1313         // This phase is complete.
1314         
1315         break;
1316       }
1317       
1318       // Sleep for a predefined period.
1319       
1320       try
1321       {
1322         Thread.sleep (mThreadMonitorInterval);
1323       }
1324       catch (InterruptedException e)
1325       {
1326       }
1327     }
1328     
1329     return (true);
1330   }
1331   
1332   //-------------------------------------
1333   /***
1334    * This method starts the appropriate number of import worker threads.
1335    */
1336   private void terminateImportWorkerThreads ()
1337   {
1338     // Interrupt the threads.
1339     
1340     for (int index = 0; index < mImportWorkerThreads.length; index++)
1341     {
1342       if (mImportWorkerThreads[index].isAlive())
1343       {
1344         mImportWorkerThreads[index].interrupt();
1345       }
1346     }
1347     
1348     // Wait on them to stop.
1349     
1350     for (int index = 0; index < mImportWorkerThreads.length; index++)
1351     {
1352       try
1353       {
1354         mImportWorkerThreads[index].join();
1355       }
1356       catch (InterruptedException e)
1357       {
1358       }
1359     }
1360     
1361     return;
1362   }
1363 
1364   public synchronized void notifyThreadStatus (int pThreadIndex, String pName, int pStatus)
1365   {
1366     mImportWorkerThreadsStatus[pThreadIndex] = pStatus;
1367   }
1368 
1369   public synchronized void processFailedDeletions ()
1370   {
1371     int pass = 1;
1372     List toRemove = mFailedDeletions;
1373     ImportItem importItem;
1374     MutableRepository targetRepository = (MutableRepository) getTargetRepository();
1375     boolean rollback = true;
1376     RepositoryItem itemToRemove = null;
1377     
1378     if (toRemove.size() == 0)
1379     {
1380       return;
1381     }
1382     
1383     while (!toRemove.isEmpty() && pass < 25)
1384     {
1385       Iterator iterator = toRemove.iterator();
1386       
1387       while (iterator.hasNext())
1388       {
1389         TransactionDemarcation transactionDemarcation = new TransactionDemarcation();
1390 
1391         try
1392         {
1393           transactionDemarcation.begin (getTransactionManager(),TransactionDemarcation.REQUIRED);
1394             
1395           importItem = (ImportItem) iterator.next();
1396 
1397           itemToRemove = targetRepository.getItem (importItem.getItemId(), importItem.getItemDescriptor());
1398           
1399           if (itemToRemove != null)
1400           {
1401             RepositoryUtils.removeReferencesToItem (itemToRemove);
1402             targetRepository.removeItem (importItem.getItemId(), importItem.getItemDescriptor());
1403           }
1404 
1405           rollback = false;
1406         }
1407         catch (RepositoryException e)
1408         {
1409           // Failed to remove item. It is probably used as a reference. Tr it again later.
1410         } 
1411         catch (TransactionDemarcationException e)
1412         {
1413           // Transaction failed.
1414         }
1415         finally
1416         {
1417           try
1418           {
1419             transactionDemarcation.end (rollback);
1420             
1421             if (!rollback)
1422             {
1423               iterator.remove();
1424             }
1425           }
1426           catch (TransactionDemarcationException e)
1427           {
1428           }
1429         }
1430       } // While
1431 
1432       pass++;
1433     }
1434   }
1435 
1436   //-------------------------------------
1437   /***
1438    * This method segments the import file into chunks of items. Each chunk is 
1439    * stored in a temporary file for processing. Chunk size is dictated by
1440    * the mItemBatchSize property.
1441    */
1442   private int segmentImportFile ()
1443   {
1444     File importFile = null;
1445     int segmentCount = 0;
1446     int itemCount = 0;
1447     File segmentFile = null;
1448     FileWriter segmentFileWriter = null;
1449     String segmentFilename = null;
1450     boolean createNewFile = true;
1451     boolean writeLineToRecord = false;
1452     String line;
1453     ArrayList additions = new ArrayList ();
1454     ArrayList others = new ArrayList ();
1455     StringBuffer record = new StringBuffer ();
1456     boolean addRecord = false;
1457     
1458     int numberOfCatalogItems = 0;
1459     int numberOfCategoryItems = 0;
1460     int numberOfProductItems = 0;
1461     int numberOfSkuItems = 0;
1462     int numberOfMediaExternalItems = 0;
1463     int numberOfFolderItems = 0;
1464     
1465     mTotalAssets = 0;
1466 
1467     // Check that the import file has been set.
1468     
1469     if (getImportFilename() == null)
1470     {
1471       System.out.println ("No import file specified.");
1472       return (0);
1473     }
1474 
1475     // Check that the specified import file exists. 
1476     
1477     importFile = new File (getImportFilename());
1478       
1479     if (!importFile.exists())
1480     {
1481       System.out.println ("The specified import file does not exist.");
1482       return (0);
1483     }
1484     
1485     // Read the import file line by line.
1486     
1487     try
1488     {
1489       BufferedReader bufferedReader = new BufferedReader (new FileReader (importFile));
1490 
1491       while ((line = bufferedReader.readLine()) != null)
1492       {
1493         // Look for any of the start item tags in this line.
1494 
1495         if (line.contains (M_TAG_ADD_ITEM_START) ||
1496             line.contains(M_TAG_UPDATE_ITEM_START) || line.contains(M_TAG_REMOVE_ITEM_START))
1497         {
1498           // Establish the item type.
1499           
1500           if (line.contains (M_ITEM_CATALOG))
1501           {
1502             numberOfCatalogItems++;
1503           }
1504           else if (line.contains (M_ITEM_CATEGORY))
1505           {
1506             numberOfCategoryItems++;
1507           }
1508           else if (line.contains (M_ITEM_PRODUCT))
1509           {
1510             numberOfProductItems++;
1511           }
1512           else if (line.contains (M_ITEM_SKU))
1513           {
1514             numberOfSkuItems++;
1515           }
1516           else if (line.contains (M_ITEM_MEDIA_EXTERNAL))
1517           {
1518             numberOfMediaExternalItems++;
1519           }
1520           else if (line.contains (M_ITEM_FOLDER))
1521           {
1522             numberOfFolderItems++;
1523           }
1524           
1525           // Create a new record.
1526           
1527           record = new StringBuffer ();
1528           
1529           record.append (line + "\n");
1530           
1531           if (line.contains (M_TAG_ADD_ITEM_START))
1532           {
1533             addRecord = true;  
1534           }
1535           else
1536           {
1537             addRecord = false;
1538           }
1539 
1540           // Check if a new file needs to be created.
1541           
1542           if (createNewFile)
1543           {
1544             // Create the next file in the sequence.
1545             
1546             segmentFilename = M_SEGMENT_FILE_STUB + (segmentCount + 1) + M_SEGMENT_FILE_EXTENSION;
1547             segmentFile = new File (mImportDirectory, segmentFilename);
1548             segmentFile.createNewFile();
1549             segmentFileWriter = new FileWriter (segmentFile, false);
1550             
1551             // Write the headers
1552             
1553             segmentFileWriter.write ("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>" + "\n");
1554             segmentFileWriter.write ("<!DOCTYPE gsa-template SYSTEM \"dynamosystemresource:/atg/dtds/gsa/gsa_1.0.dtd\">" + "\n");
1555             segmentFileWriter.write ("<gsa-template>" + "\n");
1556             segmentFileWriter.flush ();
1557             
1558             segmentCount++;
1559             
1560             createNewFile = false;
1561           }
1562           
1563           writeLineToRecord = true;
1564 
1565           itemCount++;
1566           mTotalAssets++;
1567 
1568           if (itemCount >= getItemBatchSize())
1569           {
1570             createNewFile = true;
1571           }
1572         }
1573         else if (line.contains (M_TAG_ADD_ITEM_END) ||
1574                   line.contains(M_TAG_UPDATE_ITEM_END) || line.contains(M_TAG_REMOVE_ITEM_END))
1575         {
1576           record.append (line + "\n");
1577           
1578           if (addRecord)
1579           {
1580             additions.add (record.toString());
1581           }
1582           else
1583           {
1584             others.add (record.toString());
1585           }
1586           
1587           writeLineToRecord = false;
1588 
1589           // If a new file is pending, write the footers and close the current file.
1590           
1591           if (createNewFile)
1592           {
1593             // Write the records. Start with the additions.
1594             
1595             if (additions.size() > 0)
1596             {
1597               segmentFileWriter.write ("<import-items>\n");
1598               
1599               Iterator additionsIterator = additions.iterator();
1600               
1601               while (additionsIterator.hasNext())
1602               {
1603                 String additionString = (String) additionsIterator.next();
1604                 segmentFileWriter.write (additionString + "\n");
1605               }
1606 
1607               segmentFileWriter.write ("</import-items>\n");
1608             }
1609               
1610             // Write the records. Start with the additions.
1611             
1612             if (others.size() > 0)
1613             {
1614               Iterator othersIterator = others.iterator();
1615               
1616               while (othersIterator.hasNext())
1617               {
1618                 String otherString = (String) othersIterator.next();
1619                 segmentFileWriter.write (otherString + "\n");
1620               }
1621             }
1622             
1623             // Clear out the arrays.
1624             
1625             additions.clear();
1626             others.clear();
1627               
1628             // Write the footers.
1629             
1630             segmentFileWriter.write ("</gsa-template>" + "\n");
1631             segmentFileWriter.flush ();
1632             segmentFileWriter.close();
1633             
1634             itemCount = 0;
1635           }
1636         }
1637         else if (writeLineToRecord)
1638         {
1639           record.append (line + "\n");
1640         }
1641       }
1642       
1643       // Ok, we're done, check if there is still a file to be written.
1644       
1645       if (createNewFile == false)
1646       {
1647         if (additions.size() > 0)
1648         {
1649           segmentFileWriter.write ("<import-items>\n");
1650           
1651           Iterator additionsIterator = additions.iterator();
1652           
1653           while (additionsIterator.hasNext())
1654           {
1655             String additionString = (String) additionsIterator.next();
1656             segmentFileWriter.write (additionString + "\n");
1657           }
1658 
1659           segmentFileWriter.write ("</import-items>\n");
1660         }
1661           
1662         // Write the records. Start with the additions.
1663         
1664         if (others.size() > 0)
1665         {
1666           Iterator othersIterator = others.iterator();
1667           
1668           while (othersIterator.hasNext())
1669           {
1670             String otherString = (String) othersIterator.next();
1671             segmentFileWriter.write (otherString + "\n");
1672           }
1673         }
1674         
1675         segmentFileWriter.write ("</gsa-template>" + "\n");
1676         segmentFileWriter.flush ();
1677         segmentFileWriter.close();        
1678       }
1679     }
1680     catch (IOException io)
1681     {
1682       System.out.println ("IOException: " + io.getMessage());
1683     }
1684     
1685     return segmentCount;
1686   }
1687 
1688   private boolean createReferenceItemGenerator ()
1689   {
1690     boolean createdSuccessfully = true;
1691     
1692     // Initialise the ReferenceItemGenerator 
1693     
1694     mReferenceItemGenerator = new ReferenceItemGenerator (this);
1695     
1696     try
1697     {
1698       mReferenceItemGenerator.initialiseReferenceItemGenerator ();
1699     }
1700     catch (RepositoryException e)
1701     {
1702       System.out.println ("SERVICE: RepositoryException: " + e.getMessage());
1703       createdSuccessfully = false;
1704     }
1705     catch (IOException e)
1706     {
1707       System.out.println ("SERVICE: IOException: " + e.getMessage());
1708       createdSuccessfully = false;
1709     }  
1710     
1711     return (createdSuccessfully);
1712   }
1713   
1714   private boolean createFailedItemLogFile ()
1715   {
1716     boolean success = true;
1717     String failedItemsFilename = getImportDirectory() + File.separator + M_FAILURES_FILENAME;
1718     
1719     File failedItemsFile = new File (failedItemsFilename);
1720     
1721     try
1722     {
1723       failedItemsFile.createNewFile();
1724       mFailedItemsFileWriter = new FileWriter (failedItemsFile, false);
1725     }
1726     catch (IOException e)
1727     {
1728       System.out.println ("IOException: " + e.getMessage());
1729       return (false);
1730     }    
1731     
1732     return (true);
1733   }
1734 
1735   public synchronized void logBatchFailure (int pSegmentIndex, int pPhase)
1736   {
1737     float errorPercentage = 0;
1738     
1739     logFailureMessage ("======== FAILED BATCH ======== (Phase " + pPhase + ")\n");
1740     logFailureMessage ("BATCH FILE: " + M_SEGMENT_FILE_STUB + pSegmentIndex + M_SEGMENT_FILE_EXTENSION + "\n");
1741     logFailureMessage ("ERROR MESSAGE: Batch rejected or import cancellation received\n");
1742 
1743     mFailedBatches++;
1744     
1745     // Check if the failed batches has exceeded the threshold percentage.
1746     
1747     errorPercentage = ((float) mFailedBatches / (float) mSegmentCount) * 100;
1748 
1749     if (errorPercentage >= getErrorThresholdPerImport())
1750     {
1751       // The number of batches rejected has surpassed the limit so return false to cancel the import.
1752       
1753       System.out.println ("SERVICE: The import error threshold has been reached. Cancelling the import... ");
1754       mErrorThresholdReached = true;
1755       cancelImport ();
1756     }
1757   }
1758 
1759   public void logFailedItem (ImportFailedItem pFailedItem, int pPhase)
1760   {
1761     logFailureMessage ("======== FAILED ITEM ======== (Phase " + pPhase + ")\n");
1762     logFailureMessage ("TYPE: " + pFailedItem.getItemDescriptor() + "\n");
1763     logFailureMessage ("ID: " + pFailedItem.getItemId() + "\n");
1764       
1765     switch (pFailedItem.getAction())
1766     {
1767       case ImportItem.M_ACTION_ADD:
1768         
1769         logFailureMessage ("ACTION: add-item" + "\n");
1770 
1771         break;
1772 
1773       case ImportItem.M_ACTION_UPDATE:
1774           
1775         logFailureMessage ("ACTION: update-item" + "\n");
1776 
1777         break;
1778         
1779       case ImportItem.M_ACTION_DELETE:
1780           
1781         logFailureMessage ("ACTION: remove-item" + "\n");
1782 
1783         break;
1784     }
1785       
1786     logFailureMessage ("BATCH FILE: " + pFailedItem.getBatchFilename() + "\n");
1787     logFailureMessage ("ERROR MESSAGE: " + pFailedItem.getMessage() + "\n");
1788   }
1789 
1790   public synchronized void logFailureMessage (String pMessage)
1791   {
1792     try
1793     {
1794       mFailedItemsFileWriter.write (pMessage);
1795       mFailedItemsFileWriter.flush();
1796     }
1797     catch (IOException e)
1798     {   
1799     }
1800   }
1801   
1802   private void deleteProject ()
1803   {
1804     if (mProcess.getProject() != null)
1805     {
1806       try
1807       {
1808         mProcess.getProject().delete (mNewUser.toString());
1809       }
1810       catch (Exception e)
1811       {     
1812       }
1813     }
1814   }
1815   
1816   private boolean disableIndexes ()
1817   {
1818     String indexQueryText;
1819     String indexDisableText;
1820     PreparedStatement indexQueryStatement; 
1821     PreparedStatement indexDisableStatement; 
1822     ResultSet indexResults;
1823     String indexName;
1824     Iterator indexIterator;
1825 
1826     // Connect to the database
1827     
1828     if (databaseConnect () == false)
1829     {
1830       return (false);
1831     }
1832     
1833     mIndexNames = new ArrayList (); 
1834     
1835     // Query to get the index names (skip the primary constraints and the LOB indexes)
1836 
1837     try
1838     {
1839       indexQueryText = "select a.index_name from user_indexes a, user_constraints b " +
1840                             "where b.CONSTRAINT_NAME != a.index_name and " +
1841                             "b.CONSTRAINT_TYPE = 'P' and " +
1842                             "a.table_name = b.table_name and " +
1843                             "a.generated = 'N' and " +
1844                             "a.INDEX_TYPE = 'NORMAL'";
1845 
1846       indexQueryStatement = mDatabaseConnection.prepareStatement (indexQueryText);
1847       indexResults = indexQueryStatement.executeQuery();
1848 
1849       while (indexResults.next())
1850       {
1851         indexName = indexResults.getString (1);
1852         mIndexNames.add (indexName);
1853       }
1854 
1855       indexResults.close();
1856       indexQueryStatement.close();
1857     }
1858     catch (SQLException e)
1859     {
1860       System.out.println ("SQLException when querying: " + e.getMessage());
1861       return (false);
1862     }
1863     
1864     // Process the indexes.
1865     
1866     try
1867     {
1868       indexIterator = mIndexNames.iterator();
1869     
1870       while (indexIterator.hasNext())
1871       {
1872         indexName = (String) indexIterator.next();
1873       
1874         indexDisableText = "alter index " + indexName + " unusable";
1875         indexDisableStatement = mDatabaseConnection.prepareStatement (indexDisableText);
1876         indexDisableStatement.executeUpdate();
1877         indexDisableStatement.close();
1878       }
1879     }
1880     catch (SQLException e)
1881     {
1882       System.out.println ("SQLException when disabling: " + e.getMessage());
1883       return (false);
1884     }
1885     
1886     // Disconnect from the database
1887     
1888     databaseDisconnect ();
1889     
1890     return (true);
1891   }
1892   
1893   private boolean rebuildIndexes ()
1894   {
1895     String indexRebuildText;
1896     PreparedStatement indexRebuildStatement; 
1897     String indexName;
1898     Iterator indexIterator;
1899 
1900     // Connect to the database
1901     
1902     if (databaseConnect () == false)
1903     {
1904       return (false);
1905     }
1906     
1907     // Process the indexes.
1908     
1909     try
1910     {
1911       indexIterator = mIndexNames.iterator();
1912     
1913       while (indexIterator.hasNext())
1914       {
1915         indexName = (String) indexIterator.next();
1916       
1917         indexRebuildText = "alter index " + indexName + " rebuild";
1918         indexRebuildStatement = mDatabaseConnection.prepareStatement (indexRebuildText);
1919         indexRebuildStatement.executeUpdate();
1920         indexRebuildStatement.close();
1921       }
1922     }
1923     catch (SQLException e)
1924     {
1925       System.out.println ("SQLException when rebuilding: " + e.getMessage());
1926       return (false);
1927     }
1928 
1929     // Disconnect from the database
1930     
1931     databaseDisconnect ();
1932     
1933     return (true);
1934   }
1935   
1936   private boolean databaseConnect ()
1937   {
1938     try
1939     {
1940       Class.forName (mDatabaseDriver);
1941     }
1942     catch (ClassNotFoundException e)
1943     {
1944       System.out.println ("ClassNotFoundException: " + e.getMessage());
1945       return (false);
1946     }
1947     
1948     try
1949     {
1950       mDatabaseConnection = DriverManager.getConnection (mDatabaseUrl, mDatabaseUsername,
1951                                                                             mDatabasePassword);
1952     }
1953     catch (SQLException e)
1954     {
1955       System.out.println ("SQLException: " + e.getMessage());
1956       return (false);
1957     }
1958     
1959     return (true);
1960   }
1961 
1962   private boolean databaseDisconnect ()
1963   {
1964     try
1965     {
1966       mDatabaseConnection.close ();
1967     }
1968     catch (SQLException e)
1969     {
1970       System.out.println ("Failed to disconnect from the database: " + e.getMessage());
1971       return (false);
1972     }
1973     
1974     return (true);
1975   }
1976   
1977   public static void main(String[] args)
1978   {
1979     ImportService service = new ImportService();
1980     //service.method ();
1981     
1982     service.mDatabaseDriver="oracle.jdbc.driver.OracleDriver";
1983     service.mDatabaseUrl="jdbc:oracle:thin:@McErlean-60:1521:ADMIN";
1984     service.mDatabaseUsername="publishing";
1985     service.mDatabasePassword="publishing";
1986 
1987     service.disableIndexes();
1988     service.rebuildIndexes();
1989   }  
1990 }