Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/flexstor/flexdbserver/services/asset/ImageConvertService.java


1   /*
2    * ImageConvertService.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.Vector;
14  
15  import com.flexstor.common.constants.AssetRolesI;
16  import com.flexstor.common.data.ActionData;
17  import com.flexstor.common.data.ActionResult;
18  import com.flexstor.common.data.ejb.disguiserecord.AssetRoleData;
19  import com.flexstor.common.data.ejb.disguiserecord.AudioRoleData;
20  import com.flexstor.common.data.ejb.disguiserecord.DisguiseAssetRecordData;
21  import com.flexstor.common.data.ejb.disguiserecord.DisguiseRecordData;
22  import com.flexstor.common.data.ejb.disguiserecord.ImageRoleData;
23  import com.flexstor.common.data.ejb.disguiserecord.LayoutRoleData;
24  import com.flexstor.common.data.ejb.disguiserecord.VideoRoleData;
25  import com.flexstor.common.errorlogger.FlexError;
26  import com.flexstor.common.importprocessor.ImportCtlData;
27  import com.flexstor.common.importprocessor.ImportData;
28  import com.flexstor.common.importprocessor.ImportResult;
29  import com.flexstor.common.io.xfile.FlexXFile;
30  import com.flexstor.common.resources.Resources;
31  import com.flexstor.common.services.ServiceArgumentsI;
32  import com.flexstor.common.settings.Settings;
33  import com.flexstor.common.util.Diagnostic;
34  import com.flexstor.common.util.FlexDbServerHost;
35  import com.flexstor.common.util.ServerList;
36  import com.flexstor.flexdbserver.importprocessor.ConversionOptions;
37  import com.flexstor.flexdbserver.services.Service;
38  import com.flexstor.flexdbserver.services.ServiceContext;
39  import com.flexstor.flexdbserver.services.io.ImportConvert;
40  import com.flexstor.flexdbserver.util.PathBuilder;
41  
42  /**
43   * <P>
44   * AlchemyConvertService <BR>
45   * <BLOCKQUOTE>
46   *    Invokes the Alchemy utility for the files specified and creates thumbnail images for each of them.
47   *    Also obtains display information about the input file. <BR>
48   *     
49   *    Different image convert applications can be plugged into this service. <BR>
50   *    The service requires the following key/value pair lines as output of the command line 
51   *    application being invoked (this is an example): <BR>
52   *    <BLOCKQUOTE>
53   *                Type: JPEG <BR>
54   *                Mode: Truecolour <BR>
55   *                Width: 640 <BR>
56   *                Height: 430 <BR>
57   *                BitsPerPixel: 24 <BR>
58   *                DPIX: 72 <BR>
59   *                DPIY: 72 <BR>
60   *                FileSize: 203189 <BR>
61   *    </BLOCKQUOTE>
62   *    The result must be sent to standard output. <BR>
63   *    The keys do not required to be with the capitalization shown. <BR>
64   *    Make sure a colon is used, not an equal sign. <BR>
65   *    Note that DPIX and DPIY can be substituted with DPCX and DPCY if this values are given in 
66   *    centimeters rather than inches. <BR>
67   *    
68   * </BLOCKQUOTE>
69   * </P>
70   *
71   * Configurable Properties in roletype_services.config <BR>
72   *
73   * <TABLE BORDER="1" CELLPADDING="3" CELLSPACING="3">
74   * <CAPTION ALIGN=TOP>
75   *    <B> In/Out Properties for Assets </B>
76   * </CAPTION>
77   *     <TR>
78   *        <FONT SIZE=+1><B>
79   *        <TH WIDTH="120">Attribute</TH>
80   *                                   <TH WIDTH="30">IN</TH>           <TH WIDTH="30">OUT</TH>          <TH WIDTH="30">Default IN</TH>  <TH WIDTH="30">Default OUT</TH>
81   *        </B></FONT>
82   *     </TR>
83   *     <TR>
84   *        <TH ALIGN=LEFT><FONT SIZE=+1><B>ROLE</B></FONT></TH>
85   *                                   <TD ALIGN=CENTER> &nbsp </TD>    <TD ALIGN=CENTER> &nbsp </TD>    <TD ALIGN=CENTER> ALL </TD>      <TD ALIGN=CENTER> &nbsp </TD>
86   *     </TR>
87   *     <TR><TH> Highres </TH>        <TD ALIGN=CENTER> X </TD>        <TD ALIGN=CENTER> X </TD>        <TD ALIGN=CENTER> &nbsp </TD>    <TD ALIGN=CENTER> &nbsp </TD></TR>
88   *     <TR><TH> Lowres </TH>         <TD ALIGN=CENTER> X </TD>        <TD ALIGN=CENTER> X </TD>        <TD ALIGN=CENTER> &nbsp </TD>    <TD ALIGN=CENTER> &nbsp </TD></TR>
89   *     <TR><TH> Thumbnail </TH>      <TD ALIGN=CENTER> X </TD>        <TD ALIGN=CENTER> X </TD>        <TD ALIGN=CENTER> &nbsp </TD>    <TD ALIGN=CENTER> X </TD></TR>
90   *     <TR><TH> Layout </TH>         <TD ALIGN=CENTER> X </TD>        <TD ALIGN=CENTER> X </TD>        <TD ALIGN=CENTER> &nbsp </TD>    <TD ALIGN=CENTER> &nbsp </TD></TR>
91   *     <TR><TH> Video </TH>          <TD ALIGN=CENTER> &nbsp </TD>    <TD ALIGN=CENTER> &nbsp </TD>    <TD ALIGN=CENTER> &nbsp </TD>    <TD ALIGN=CENTER> &nbsp </TD></TR>
92   *     <TR><TH> Audio </TH>          <TD ALIGN=CENTER> &nbsp </TD>    <TD ALIGN=CENTER> &nbsp </TD>    <TD ALIGN=CENTER> &nbsp </TD>    <TD ALIGN=CENTER> &nbsp </TD></TR>
93   *     <TR>
94   *        <TH ALIGN=LEFT><FONT SIZE=+1><B>TYPE</B></FONT></TH>
95   *                                   <TD ALIGN=CENTER> X </TD>        <TD ALIGN=CENTER> X </TD>        <TD ALIGN=CENTER> ALL </TD>    <TD ALIGN=CENTER> &nbsp </TD></TR>
96   *     </TR>
97   *     <TR>
98   *        <TH ALIGN=LEFT><FONT SIZE=+1><B>FLAG</B></FONT></TH>
99   *     </TR>
100  *     <TR><TH> PARENT </TH>         <TD ALIGN=CENTER> X </TD>        <TD ALIGN=CENTER> X </TD>        <TD ALIGN=CENTER> &nbsp </TD>    <TD ALIGN=CENTER> &nbsp </TD></TR>
101  *     <TR><TH> CHLDREN </TH>        <TD ALIGN=CENTER> X </TD>        <TD ALIGN=CENTER> X </TD>        <TD ALIGN=CENTER> &nbsp </TD>    <TD ALIGN=CENTER> X </TD></TR>
102  *     <TR><TH> ALL </TH>            <TD ALIGN=CENTER> X </TD>        <TD ALIGN=CENTER> X </TD>        <TD ALIGN=CENTER> &nbsp </TD>    <TD ALIGN=CENTER> &nbsp </TD></TR>
103  *     <TR><TH> TEMP_PARENT </TH>    <TD ALIGN=CENTER> X </TD>        <TD ALIGN=CENTER> X </TD>        <TD ALIGN=CENTER> &nbsp </TD>    <TD ALIGN=CENTER> &nbsp </TD></TR>
104  *     <TR><TH> TEMP_CHILDREN </TH>  <TD ALIGN=CENTER> X </TD>        <TD ALIGN=CENTER> X </TD>        <TD ALIGN=CENTER> &nbsp </TD>    <TD ALIGN=CENTER> &nbsp </TD></TR>
105  *     <TR><TH> TEMP_ALL </TH>       <TD ALIGN=CENTER> X </TD>        <TD ALIGN=CENTER> X </TD>        <TD ALIGN=CENTER> &nbsp </TD>    <TD ALIGN=CENTER> &nbsp </TD></TR>
106  * </TABLE>
107  *
108  * <P>
109  * <BLOCKQUOTE>
110  *    configfile: Path to configuration file holding Alchemy related parameters
111  *    (optional; defaults to conversion.cfg file for the hot directory). <BR>
112  *    Legal values: Full path to configuration file
113  * </P>
114  *
115  * <P>
116  *    destination: Path for output thumbnail file (optional; defaults to thumbtarget
117  *    property in the input control [*.ctl] file). <BR>
118  *    Legal values: Full path to output directory
119  * </BLOCKQUOTE>
120  * </P>
121  *
122  * <P>
123  * Input Data Object <BR>
124  * <BLOCKQUOTE>
125  *    com.flexstor.common.importprocessor.ImportData
126  * </BLOCKQUOTE>
127  * </P>
128  *
129  * <P>
130  * Output Data Object <BR>
131  * <BLOCKQUOTE>
132  *    com.flexstor.common.importprocessor.ImportResult
133  * </BLOCKQUOTE>
134  * </P>
135  * Programmable Properties (passed inside data object) <BR>
136  * <BLOCKQUOTE>
137  *    Global Properties (apply to all assets) <BR>
138  * <BLOCKQUOTE>
139  * <P>
140  *       "intervaltimer_timeout" : 
141  *       A user-specified property in roletype_services.config that defines the timeout period for
142  *       the watch-dog timer that interrupts the Alchemy process if it hangs.
143  *       Data type: int <BR>
144  *       Legal values: time (seconds) <BR>
145  * </P>
146  * </BLOCKQUOTE>
147  * </BLOCKQUOTE>
148  */
149  
150 public class ImageConvertService
151    implements Service
152 {
153    // To get the version number from MKS
154    public final static String IDENTIFIER="$Id: ImageConvertService.java,v 1.5 2003/08/11 02:22:29 aleric Exp $";
155 
156    public static final String CONVERT  = "Image Conversion";
157    public static       String sVersion = " ImageConvertService - 02-24-99(1)";
158 
159    protected ServiceContext context;
160    protected String fileSeparator;
161    protected int id;
162    
163    private String     sThisService    = "";
164 
165    private String     sFormat         = " ";
166    private String     sThumbLocation  = " ";
167    private String     sThumbServer    = " ";
168    private String     sThumbName      = " ";
169    private String     sThumbSize      = " ";
170    private String     sThumbPath      = " ";
171 
172    // Image File Attributes
173    private String sPrimaryFormat     = " ";
174    private String sPrimaryDPIX       = " ";
175    private String sPrimaryDPIY       = " ";
176    private String sPrimaryWidth      = " ";
177    private String sPrimaryHeight     = " ";
178    private String sPrimaryColorDepth = " ";
179    private String sPrimaryColorSpace = " ";
180    private String sPrimaryFileSize   = " ";
181 
182    private ConversionOptions refConversionOptions = null;
183 
184    // "1" = UNIX version, "0" = Windows version
185    private int         nOemAlchemy          = 1;  // default to UNIX
186    private String      sTranslator          = "";
187    private String      sTargetPath          = "";
188    private String      sConfigFile          = "";
189 
190    protected boolean   successful           = true;
191    protected boolean   bUpdateTargetPath    = true;
192    protected String    sExtType             = "";
193    
194    protected ImportCtlData refCtlData     = null;
195    protected ImportData    refImportData  = null;
196    
197    
198    /**
199     * Calls before the service is initialized (before initData is called) to 
200     * pass information about the environment in which the service is running.
201     * This environment consists of information about the properties set for the
202     * service in one of these files (services.config, roletype_services.config,
203     * or *.ctl), plus methods to access other information such as an instance
204     * of the service broker to invoke other services, the transaction id for
205     * the service, file separator character and local path for the installation
206     * directory and configuration directory.
207     * 
208     * @param context Holds information about the environment in which the service
209     *                is running.
210     */
211    public void setServiceContext( ServiceContext context )
212    {
213       this.context = context;
214       fileSeparator = context.getFileSeparator();
215       id = context.getTransactionId();
216    }
217    
218    /**
219    * A data initialization method called at the beginning of the service.
220    * The input argument, ActionData must be cast into its subclass, ConvertData
221    * in order to extract the ConvertService specific data from it.
222    */
223    public void initData(ActionData actionData)
224    {
225       if ( (Settings.getString( Settings.SYSTEM_OS )).equals("UNIX") )
226          nOemAlchemy = 1; // tell Convert to use unixExecute()
227       else
228          nOemAlchemy = 0; // tell Convert to use dosExecute()
229 
230       // cast the data object to a convert data wrapper
231       refImportData = (ImportData) actionData;
232 
233       // Get the reference to the .CTL data object
234       refCtlData = refImportData.getCtlDataRef();
235 
236       // Get the config file name defined in the services.config file; if one is not present
237       // use the one listed in the CTL data.
238       sConfigFile = context.getProperty( "configfile" );
239       if ( sConfigFile == null || sConfigFile.equals("") )
240          sConfigFile  = refCtlData.getValuePerKey("CONTROLFILESPATH") + refCtlData.getValuePerKey("CONFIGFILE");
241 
242       //5882=Alchemy Convert Service
243       sThisService = Resources.get(5882) + " (" + id + ")";
244 
245    } // initData
246 
247    /**
248    * The start of the Convert Service.
249    */
250    public ActionResult go()
251    {
252       Diagnostic.trace(Diagnostic.APPSERVER_SERVICES, "AlchemyConvertStarting");
253       // Need to read the .cfg conversion file to get all of the parameters
254       // that Alchemy needs to do the conversions
255       // If we could not read the config file return from the convert service.
256       // We already sent the response object back if it was necessary
257       if (!readCfgFile())
258       {
259          ImportResult response = new ImportResult(false);
260          response.setImportData(refImportData);
261 
262          return response;
263       }
264 
265       // Now that we have read in the .cfg file successfully, prepare to
266       // read in the input files and process them with Alchemy.
267       // If successful == false at least one file didn't convert correctly.
268       successful = true;      
269       
270       // Get a reference to the DisguiseRecordData so we can get the assets
271       // Also get Role, Type and Flag values from property list (AssetService)
272       DisguiseRecordData refDisguiseRecordData = refImportData.getDisguiseRecordRef();
273       String sRoleIn  = context.getProperty(ServiceArgumentsI.ROLE_DATA_SOURCE);
274       String sTypeIn  = context.getProperty(ServiceArgumentsI.TYPE_DATA_SOURCE);
275       String sFlagIn  = context.getProperty(ServiceArgumentsI.FLAG_DATA_SOURCE);
276       String sRoleOut = context.getProperty(ServiceArgumentsI.ROLE_DATA_DESTINATION);
277       String sTypeOut = context.getProperty(ServiceArgumentsI.TYPE_DATA_DESTINATION);
278       String sFlagOut = context.getProperty(ServiceArgumentsI.FLAG_DATA_DESTINATION);
279       Vector vAssetsIn =  null;
280       Vector vAssetsOut =  null;
281       
282       Diagnostic.trace(Diagnostic.APPSERVER_SERVICES, "RoleIn = " + sRoleIn);
283       Diagnostic.trace(Diagnostic.APPSERVER_SERVICES, "TypeIn = " + sTypeIn);
284       Diagnostic.trace(Diagnostic.APPSERVER_SERVICES, "FlagIn = " + sFlagIn);
285       Diagnostic.trace(Diagnostic.APPSERVER_SERVICES, "RoleOut = " + sRoleOut);
286       Diagnostic.trace(Diagnostic.APPSERVER_SERVICES, "TypeOut = " + sTypeOut);
287       Diagnostic.trace(Diagnostic.APPSERVER_SERVICES, "FlagOut = " + sFlagOut);
288       
289       if(refDisguiseRecordData != null)
290       {
291          if(sRoleIn == null || sTypeIn == null || sFlagIn == null)
292          {
293             successful = false;
294          }
295          else
296          { // Get the assets 
297             vAssetsIn = refDisguiseRecordData.getAssets(sRoleIn, sTypeIn, sFlagIn);
298             vAssetsOut = refDisguiseRecordData.getAssets(sRoleOut, sTypeOut, sFlagOut);
299             if(vAssetsIn != null)
300             {
301                DisguiseAssetRecordData targetAsset = null;
302 
303                // Try to get the thumbnail target set in the service properties (configuration files)
304                // as the "destination" property; if not found in services.config use the value in the ctl file.
305                String sThumbtarget = context.getProperty("destination");
306                if ( sThumbtarget == null || sThumbtarget.equals("") )
307                   sThumbtarget = refCtlData.getValuePerKey("thumbtarget");
308 
309                if ( sThumbtarget.endsWith( fileSeparator ) )
310                   sThumbtarget = sThumbtarget.substring( 0, sThumbtarget.length() - 1 );
311 
312                String sPrimaryFileListBase = refCtlData.getValuePerKey("highfilelistbase");
313                if ( sPrimaryFileListBase.endsWith( fileSeparator ) )
314                   sPrimaryFileListBase = sPrimaryFileListBase.substring( 0, sPrimaryFileListBase.length() - 1 );
315 
316                Diagnostic.trace(Diagnostic.APPSERVER_SERVICES, "ThumbTarget = " + sThumbtarget);
317                Diagnostic.trace(Diagnostic.APPSERVER_SERVICES, "HighFileListBase = " + sPrimaryFileListBase);
318 
319                // Processs each asset in each element in ImportData as required
320                for ( int i = 0; i < vAssetsIn.size(); i++ )
321                {
322                   DisguiseAssetRecordData assetIn = (DisguiseAssetRecordData)vAssetsIn.elementAt(i);
323 
324                   Diagnostic.trace(Diagnostic.APPSERVER_SERVICES, "AlchemyConvert: Getting paths");
325                   String sLocation = assetIn.getLocation();
326                   if ( sLocation.startsWith(fileSeparator) == false )
327                      sLocation = fileSeparator + sLocation;
328 
329                   DisguiseAssetRecordData assetOut = null;
330                   try
331                   {
332                      assetOut = (DisguiseAssetRecordData) vAssetsOut.elementAt(i);
333                      // If the asset out is a PARENT, then it children will be the target, otherwise
334                      // itself will be the target.
335                      if ( sFlagOut.equals( "PARENT" ) )
336                      {
337                         targetAsset = assetOut.getChildAssetNoTemp( AssetRolesI.THUMBNAIL );
338                         if ( targetAsset == null )
339                         {
340                            Diagnostic.trace(Diagnostic.APPSERVER_SERVICES, "AlchemyConvert creating new Asset");
341                            targetAsset = new DisguiseAssetRecordData();
342                            targetAsset.setBucketStructId( assetIn.getBucketStructId() );
343                            assetOut.addChildAsset( targetAsset );
344                         }
345                         else
346                            Diagnostic.trace(Diagnostic.APPSERVER_SERVICES, "AlchemyConvert updating Child Asset");
347   
348                         // Set this THUMBNAIL as the default view asset
349                         targetAsset.setDefaultView(true);
350                      }
351                      else
352                      {
353                         targetAsset = assetOut;
354                         Diagnostic.trace(Diagnostic.APPSERVER_SERVICES, "AlchemyConvert updating Asset");
355                      }
356                   }
357                   catch ( ArrayIndexOutOfBoundsException aioobe )
358                   {
359                      Diagnostic.trace(Diagnostic.APPSERVER_SERVICES, "Creating new assetOut" );
360                      // If role and type are default, use the ones in the assetIn
361                      int nRoleOutId = AssetRolesI.THUMBNAIL;
362                      if ( sRoleOut.equals( ServiceArgumentsI.DEFAULT_ROLE ) == false )
363                         nRoleOutId = getRoleId( sRoleOut );
364 
365                      if ( nRoleOutId == AssetRolesI.THUMBNAIL )
366                         // Set this THUMBNAIL as the default view asset
367                         targetAsset.setDefaultView(true);
368 
369                      if ( sTypeOut.equals( ServiceArgumentsI.DEFAULT_TYPE ) )
370                         sTypeOut = assetIn.getAssetFileType();
371 
372                      assetOut = new DisguiseAssetRecordData();
373                      assetOut.setBucketStructId(assetIn.getBucketStructId());
374                      AssetRoleData role = AssetRoleData.getAssetRoleData(nRoleOutId);
375                      role.setAssetFileType( sTypeOut );
376                      if ( sFlagOut.equals( "TEMP" ) )
377                         role.setTempRole( true );
378                      assetOut.setAssetRole( role );
379                      assetIn.addChildAsset( assetOut );
380                      targetAsset = assetOut;
381                   }
382 
383                   if ( targetAsset.getServer() != null && targetAsset.getLocation() != null && targetAsset.getFileName() != null )
384                   {
385                      sTargetPath = PathBuilder.constructPath( "", targetAsset.getLocation(), true );
386                      sThumbPath = PathBuilder.constructFilePath( "", "", targetAsset.getLocation(), targetAsset.getFileName() );
387                      bUpdateTargetPath = false;
388                   }
389                   else
390                   {
391                      sTargetPath = buildCompositeDir(sLocation, sThumbtarget, sPrimaryFileListBase);
392                      bUpdateTargetPath = true;
393                   }
394 
395                   Diagnostic.trace(Diagnostic.APPSERVER_SERVICES, "Location = " + sLocation);
396                   Diagnostic.trace(Diagnostic.APPSERVER_SERVICES, "TargetPath = " + sTargetPath);
397 
398                   // Create the Thumbnail
399                   if (convertAsset(assetIn, targetAsset) == false)
400                   {
401                      // Hard error, quit now
402                      successful = false;
403                      break;
404                   }
405                }
406             }
407             else
408                successful = false;
409          }
410       }
411       else
412          successful = false;
413       
414       // pass back the ImportData
415       ImportResult response = new ImportResult(successful); // turn off default result
416       response.setImportData(refImportData);
417       
418       return response;
419    } // go()
420       
421    /**
422    * Convert & Get Info
423    */
424    protected boolean convertAsset(DisguiseAssetRecordData refSourceAsset, DisguiseAssetRecordData targetAsset)
425    {
426       if(refSourceAsset == null)
427          return false;
428             
429       String  server     = ServerList.getDNSName( refSourceAsset.getServer() );
430       // Get the paths
431       Diagnostic.trace(Diagnostic.APPSERVER_SERVICES, "Creating the sInputPath...  The location and filename are: " + 
432                          refSourceAsset.getLocation() + ", " + refSourceAsset.getFileName());
433       String sInputPath = refSourceAsset.getLocation() + refSourceAsset.getFileName();
434       if ( sInputPath.startsWith(fileSeparator) == false )
435          sInputPath = fileSeparator + sInputPath;
436         
437       // Get The Role Data to get the AssetType
438       AssetRoleData roleData = (AssetRoleData) refSourceAsset.getAssetRole();
439       // If the host or inputpath is null, fail.  Also if the servername does not match
440       // the FlexDBServer host name, it means that the file is on another filesystem
441       // and we shouldn't convert it.
442       if ( !FlexDbServerHost.isLocalHost( server ) )
443       {
444          successful = false; // at least one file did not convert right
445          //6805=Unable to convert file: %%1. Server specified in asset record (%%2) does not match FlexDBServer host (%%3)
446          refImportData.addErrorRecord( new FlexError(FlexError.CRITICAL, sThisService, IDENTIFIER, 6805, (new String[] { sInputPath, server, FlexDbServerHost.getLocalHostName() })) );
447          return false;
448       }
449       else
450       {
451          String  sAssetType = null; 
452          if(roleData != null)
453          {
454             sAssetType = roleData.getAssetFileType();
455             Diagnostic.trace(Diagnostic.APPSERVER_SERVICES, "sAssetType is: " + sAssetType);
456          }
457          if (sInputPath  != null)
458          {
459             // Set up the conversion options data structure and process the element.
460             // If true is returned, the file either converted successfully or it had a default
461             // thumbnail specified in the conversion config file setting associating a thumbnail
462             // for a non convertable file.
463             if ( processElement(sAssetType, sInputPath) == false)
464             {
465                //5519=Unable to convert input file: %%1
466                refImportData.addErrorRecord( new FlexError(FlexError.CRITICAL, sThisService, IDENTIFIER, 5519, (new String[] { sInputPath} )) );
467             }
468          } // if if (sSourcePath != null)
469          else
470          {
471             successful = false; // at least one file did not convert right
472 
473             //5505=Null input file.
474             refImportData.addErrorRecord( new FlexError(FlexError.CRITICAL, sThisService, IDENTIFIER, 5505) );
475          }
476       } // ServerPath else
477 
478       // Create the thumbnail asset and role if necessary
479       AssetRoleData targetRole = hasRole(targetAsset);
480       if ( targetRole == null )
481       {
482          Diagnostic.trace(Diagnostic.APPSERVER_SERVICES, "Alchemy Convert creating new Role");
483          targetRole = AssetRoleData.getAssetRoleData(AssetRolesI.THUMBNAIL);
484          targetAsset.setAssetRole(targetRole);
485       }
486       else
487          Diagnostic.trace(Diagnostic.APPSERVER_SERVICES, "Alchemy Convert updating Role");
488 
489       if ( targetRole.getAssetFileType() == null )
490          targetRole.setAssetFileType( getExtensionFrom( getThumbName() ));
491 
492       targetAsset.setFileSize(stringToLong(getThumbSize()));
493 
494       if ( bUpdateTargetPath )
495       {
496          String sTNServer = getThumbServer();
497          if (sTNServer.equals(" ") == false)
498             targetAsset.setServer(sTNServer);
499          else
500             targetAsset.setServer(refSourceAsset.getServer());
501 
502          // Thumb name includes path/filename.  If default icon is used it will be found
503          // in getThumbLocation(). Otherwise, use the actual sThumbPath set in convertImage()
504          String sThumbLoc = getThumbLocation();
505 
506          if ( sThumbLoc.startsWith(fileSeparator) )
507             sThumbLoc = sThumbLoc.substring(1); // remove leading slash, if any
508          if ( !sThumbLoc.endsWith(fileSeparator) )
509             sThumbLoc += fileSeparator; // add trailing slash
510 
511          targetAsset.setLocation( sThumbLoc );
512          targetAsset.setFileName(getThumbName());
513       }
514 
515       // Set the file size if it isn't already set
516       if ( refSourceAsset.getFileSize() < 0 )
517          refSourceAsset.setFileSize( stringToLong(sPrimaryFileSize) );
518 
519       if ( roleData instanceof ImageRoleData )
520       {
521          ImageRoleData imageRoleData = (ImageRoleData) roleData;
522          Diagnostic.trace(Diagnostic.APPSERVER_SERVICES, "Setting values for " + roleData.getAssetFileType());
523          imageRoleData.setXRes( stringToFloat(sPrimaryDPIX) );
524          imageRoleData.setYRes( stringToFloat(sPrimaryDPIY) );
525          imageRoleData.setWidth( stringToFloat(sPrimaryWidth) );
526          imageRoleData.setHeight( stringToFloat(sPrimaryHeight) );
527          imageRoleData.setColorDepth( stringToFloat(sPrimaryColorDepth) );
528          imageRoleData.setColorSpace( sPrimaryColorSpace );
529          Diagnostic.trace(Diagnostic.APPSERVER_SERVICES, "----> " + imageRoleData.getXRes() + ", " + imageRoleData.getYRes() + ", " + imageRoleData.getWidth()
530                             + ", " + imageRoleData.getHeight() + ", " + imageRoleData.getColorDepth() + ", " + imageRoleData.getColorSpace());
531       }
532       return true;
533    } // convertAsset
534       
535    /**
536    * Build up the directory from the element & root paths specified.
537    * @param sLocation The element path.
538    * @param sRootPath The root path.
539    */
540    protected String buildCompositeDir(String sLocation, String sRootPath, String sListBasePath)
541    {
542       Diagnostic.trace(Diagnostic.APPSERVER_SERVICES, "sLocation, sRootPath and sListBase in buildCompositeDir: " + sLocation + ", " +
543       sRootPath + ", " + sListBasePath);
544       String sOutputPath = sRootPath;
545       String fileSeparator = System.getProperty("file.separator");
546       // Find the base path in the user specified input file path
547       if (sLocation.startsWith(sListBasePath))
548          sOutputPath += fileSeparator + sLocation.substring(sListBasePath.length() + 1);
549       else
550          sOutputPath += sLocation;
551 
552       Diagnostic.trace(Diagnostic.APPSERVER_SERVICES, "The output path from buildCompositeDir is: " + sOutputPath);
553       return sOutputPath;
554    } // buildCompositeDir
555 
556    /**
557    *
558    */
559    private boolean readCfgFile()
560    {
561       // Need to read the .cfg conversion file to get all of the parameters
562       // that Alchemy needs to do the conversions
563       refConversionOptions = new ConversionOptions(sConfigFile);
564       if ( refConversionOptions.processSection(false) )
565          return true; // we read the file OK so return true
566       else
567       {
568          //5521=Unable to read configuration input file: %%1
569          refImportData.addErrorRecord( new FlexError(FlexError.CRITICAL, sThisService, IDENTIFIER, 5521, (new String[] { sConfigFile })) );
570          return false;
571       }
572    } // readCfgFile()
573 
574    /**
575    *
576    */
577    public boolean processElement(String sAssetType, String sSourcePath)
578    {
579       // Setup translator path first, so if not found can quit now
580       sTranslator = refConversionOptions.getConversionItem("TRANSLATOR", "PATH");
581       if (sTranslator.equals("") == true)
582          return false;
583         
584       // If file is non-convertable, use its default icon for thumbnail, else convert
585       if (checkFileType(sAssetType, "NC") == false)
586       {
587          // Extract TN's         
588          if (convertImage(sSourcePath, sAssetType) == false)
589          {
590             // process element returns false if no Thumbnail was created
591             return false;
592          }
593       } // checkFileType if
594 
595       return true;
596    } // processElement
597 
598    /**
599    * Convert the specified image to a thumbnail
600    * @param imagePath The image to convert.
601    */
602    private boolean convertImage(String imagePath, String sAssetType)
603    {
604       // Get the file type in order to get the user-supplied conversion options from the config file.
605       // Use the format type specified by the last "TYPE =". If it is null, use the type returned
606       // by Alchemy.  If that is null, get the "UNKNOWN" type specified in the config file.
607       sFormat = sAssetType;
608 
609       if (sFormat.equals("") == true)
610       {
611          sFormat = refConversionOptions.getConversionItem("UNKNOWN", "TYPE");
612          if (sFormat.equals("") == true)
613          {
614             // No 'unknown' file type specified by user so:
615             // Use the 'unknown' default icon
616             checkFileType("UNKNOWN", "C");
617             return false;
618          }
619       }
620 
621       String sOptions = "";
622 
623       // Get user-provided conversion options
624       String sUserOptions = refConversionOptions.getConversionItem(sFormat, "OPTION");
625 
626       if(sUserOptions.equals("") == true)
627       {
628          // No options specified for this type so get the user-specified default
629          sUserOptions = refConversionOptions.getConversionItem("DEFAULT", "OPTION");
630          //"Using 'Default' conversion options: " + sUserOptions
631          if(sUserOptions.equals("") == true)
632          {
633             // No user-specifed default so use default output file type
634             sOptions += " -jh32 -Zm2 -o ---. --W -Za2 -Ze1 -Zo300p 300p -Yb300p -Xb300p -Z+ -+";
635          }
636          else
637             sOptions += " " + sUserOptions;
638       }
639       else
640          sOptions += " " + sUserOptions;
641 
642       // Setup output path (create it if it doesn't exist)
643       if (sTargetPath.equals("") == true)
644          return false;
645 
646       FlexXFile xOutputPath = new FlexXFile( sTargetPath );
647 
648       if (createDir(xOutputPath) == false)
649       {
650          //5501=Failure creating output directory path: %%1
651          refImportData.addErrorRecord( new FlexError(FlexError.CRITICAL, sThisService, IDENTIFIER, 5501, (new String[] { xOutputPath.getLocalPath() })) );
652          return false;
653       }
654 
655       if ( bUpdateTargetPath )
656       {
657 //         String sOutputPath = xOutputPath.getLocalPath() + fileSeparator;
658          String sOutputPath = xOutputPath.getLocalPath();
659          // Get the extension of the file to convert to from config file
660          String sExtType = getExtensionType(sFormat);
661 
662          // Get the file name (with no path and no extension)
663          String sNameOnly = getNameNoPath(imagePath);
664          String sOriginalExt = "";
665          // If there is an extension, split the filename and its extension.
666          if ( sNameOnly.indexOf('.') != -1 )
667          {
668             sOriginalExt = sNameOnly.substring( sNameOnly.lastIndexOf('.')  );
669             sNameOnly = sNameOnly.substring( 0, sNameOnly.lastIndexOf(sOriginalExt) );
670          }
671 
672          // If an output extension was set, we should find out whether we should append the extension to the
673          // file name or remove the old extension first; this will be specified by the existence of the ---.
674          // option in the sOptions String.
675          // If the output extension is set, but the --o (use input file for output) is also set, we should
676          // log an error because this is ambigious.
677          // If the output extension is not set, then use the original filename as the output file
678          if ( sExtType != null && !sExtType.equals("") )
679          {
680             if ( sOptions.indexOf( "--o" ) != -1 )
681             {
682                // Log an error
683                // 7050=%%1 failed to process. outputext and --o cannot be specified together in %%2
684                new FlexError(FlexError.CRITICAL, sThisService, IDENTIFIER, 7050, new String[] { imagePath, sConfigFile });
685                return false;
686             }
687             else if ( sOptions.indexOf( "---." ) != -1 )
688             {
689                sThumbName = sNameOnly + sOriginalExt + "." + sExtType.trim();
690 
691                // Remove the ---. option from the sOption
692                sOptions = removeOption( sOptions, "---." );
693             }
694             else
695                sThumbName = sNameOnly + "." + sExtType.trim();
696          }
697          else
698          {
699             // If an extension is not defined; remove the --o and ---. options from sOptions; there is no
700             // point on specifying them at all
701             sOptions = removeOption( sOptions, "--o" );
702             sOptions = removeOption( sOptions, "---." );
703 
704             sThumbName = sNameOnly + sOriginalExt;
705          }
706 
707          // Setup thumb path and name
708          sThumbLocation = sOutputPath;
709          sThumbPath = sOutputPath + sThumbName;
710       }
711       else
712       {
713          // If the full path to the thumbnail is specified, then remove the "--o" and "---." options from
714          // the sOptions; they are meaningless when the output file is specified
715          sOptions = removeOption( sOptions, "--o" );
716          sOptions = removeOption( sOptions, "---." );
717       }
718       
719       // Setup the translator program command line
720       String[] saProcess = ImportConvert.createCommand( sTranslator, imagePath, sThumbPath, sOptions );
721 
722       // Call the external translation program
723       // "Executing Conversion program (convert): " + sProcess
724       executeConversion(saProcess);
725 
726       // Get the thumbnail file size
727       FlexXFile fThumb = new FlexXFile(sThumbPath);
728       if (!fThumb.exists())
729       {
730          // Output default icon for unknown file type
731          if (checkFileType(sAssetType, "C") == false)
732             checkFileType("UNKNOWN", "C");
733          //"Thumbnail file does not exist : " + fThumb.toString()
734          //5514=Converted file not created: %%1
735          refImportData.addErrorRecord( new FlexError(FlexError.CRITICAL, sThisService, IDENTIFIER, 5514, (new String[] { sThumbPath })) );
736          // False because no thumbnail was created successfully
737          return false; // added for ConvertResult for Send Elements
738       } // if (!fThumb.exists())
739       else
740          sThumbSize = String.valueOf(fThumb.length());
741 
742       return true;
743    } // convertImage
744 
745    private String removeOption( String sOptions, String sOptionToRemove )
746    {
747       if ( sOptions.indexOf( sOptionToRemove ) != -1 )
748       {
749          int nEndIndex = sOptions.indexOf(sOptionToRemove);
750          int nStartIndex = nEndIndex + sOptionToRemove.length() + 1;
751          String sOptions1 = sOptions.substring( 0, nEndIndex );
752          String sOptions2 = sOptions.substring( nStartIndex );
753          sOptions = sOptions1 + sOptions2;
754       }
755       return sOptions;
756    }
757 
758    /**
759    *
760    */
761    protected String getExtensionType(String sInputType)
762    {
763       String sOutputExtension = "";
764 
765       if (sInputType.length() > 0)
766       {
767          sOutputExtension = refConversionOptions.getConversionItem(sInputType, "OUTPUTEXT");
768          if (sOutputExtension.equals(""))
769             sOutputExtension = refConversionOptions.getConversionItem("DEFAULT", "OUTPUTEXT");
770       }
771       return sOutputExtension;
772    } // getExtensionType
773 
774 
775    /**
776    *
777    */
778    protected boolean createDir(FlexXFile xOutputPath)
779    {
780       // In order to create DOS dirs, must use back-slashes
781       if (xOutputPath != null)
782       {
783          if (xOutputPath.exists() == false)
784          {
785             if (xOutputPath.mkdirs() == false)
786             {
787                //5501=Failure creating output directory path: %%1
788                refImportData.addErrorRecord( new FlexError(FlexError.CRITICAL, sThisService, IDENTIFIER, 5501, (new String[] { xOutputPath.getLocalPath() })) );
789                return false;
790             }
791          }
792       } // fOutputPath null if
793       else
794          return false;
795       return true;
796    } // createDir
797 
798    private float stringToFloat(String theString)
799    {
800       float returnVal = 0.0f;
801       try{ returnVal = Float.valueOf(theString).floatValue();} catch(NumberFormatException e){};
802       return returnVal;
803    }
804 
805    private long stringToLong(String theString)
806    {
807       long returnVal = 0;
808       try{ returnVal = Long.valueOf(theString).longValue();} catch(NumberFormatException e){};   
809       return returnVal;
810    }
811     
812    /**
813    * Do the actual image conversion creating the thumbnail.
814    * @param sCommandLine The parameter and options string for the conversion process.
815    */
816    protected boolean executeConversion(String[] saCommandLine)
817    {
818       boolean bResult = true;
819       
820       // Get the user specified value for the watchdog timer interval
821       // Timeout value is specified in seconds
822       String sTimeOut = context.getProperty("intervaltimer_timeout");
823       // If the intervaltimer_timeout property wasn't set, check for the conversion_timeout
824       // property; this is left here for backward compatibility with release 3.0.6.0 
825       if ( sTimeOut == null )
826          sTimeOut = context.getProperty("conversion_timeout");
827       
828       ImportConvert refConvert = new ImportConvert();
829 
830       Diagnostic.trace(Diagnostic.APPSERVER_SERVICES, 4, "Conversion: " + refConvert.toString(saCommandLine));
831       bResult = refConvert.executeConversion(saCommandLine, nOemAlchemy, sTimeOut);
832       if (bResult == true)
833       {
834          //sFormat = refConvert.getFormat();
835          //sPrimaryFormat = refConvert.getFormat();
836          sPrimaryDPIX       = refConvert.getDPIX();
837          sPrimaryDPIY       = refConvert.getDPIY();
838          sPrimaryWidth      = refConvert.getWidth();
839          sPrimaryHeight     = refConvert.getHeight();
840          sPrimaryColorDepth = refConvert.getColorDepth();
841          sPrimaryColorSpace = refConvert.getColorMode();
842          sPrimaryFileSize   = refConvert.getFileSize();
843       }
844       return bResult;
845    } // executeConversion
846 
847    /**
848    *
849    */
850    protected String getExtensionFrom(String sPath)
851    {
852       // Get the extension
853       int nPos = sPath.lastIndexOf(".");
854       if (nPos != -1)
855          return sPath.substring(nPos + 1);
856 
857       return "";
858    } // getExtensionFrom
859 
860   /**
861   *
862   */
863    protected String getNameNoPath(String sFullPath)
864    {
865       int nPos = sFullPath.lastIndexOf("/");
866       if (nPos != -1)
867          return sFullPath.substring(nPos + 1);
868          
869       return sFullPath;
870    } // getNameNoPath
871 
872    /**
873    *
874    */
875    protected boolean checkFileType(String sExtension, String sType)
876    {
877       // Return true if the extension is found
878       boolean bResult = false;
879 
880       int nExtIndex = -1;
881       if (sExtension.length() > 0)
882          nExtIndex = refConversionOptions.checkExtension(sExtension, sType);
883 
884       if (nExtIndex >= 0)
885       {
886          // A default icon exists
887          sThumbServer   = refConversionOptions.getDefaultIconServer(nExtIndex);
888          sThumbName     = refConversionOptions.getDefaultIconName(nExtIndex);
889          sThumbLocation = refConversionOptions.getDefaultIconLocation(nExtIndex);
890          sThumbSize     = "0";
891          bResult = true;
892       }
893       return bResult;
894    } // checkFileType
895 
896    private int getRoleId( String sRole )
897    {
898       // Get the proper Role Id
899       if ( sRole.equalsIgnoreCase("LOWRES") )
900          return AssetRolesI.LOWRES;
901       else if ( sRole.equalsIgnoreCase("THUMBNAIL") )
902          return AssetRolesI.THUMBNAIL;
903       else if ( sRole.equalsIgnoreCase("LAYOUT") )
904          return AssetRolesI.LAYOUT;
905       else if ( sRole.equalsIgnoreCase("AUDIO") )
906          return AssetRolesI.AUDIO;
907       else if ( sRole.equalsIgnoreCase("VIDEO") )
908          return AssetRolesI.VIDEO;
909       else  if ( sRole.equalsIgnoreCase("ALL") )
910          return -1;
911       else
912          return AssetRolesI.HIGHRES; // HIGHRES is the default
913    }
914 
915    private AssetRoleData hasRole( DisguiseAssetRecordData asset )
916    {
917       AssetRoleData role = asset.getAssetRole();
918       if ( role == null ||
919          (!(role instanceof ImageRoleData) &&
920             !(role instanceof LayoutRoleData) &&
921                !(role instanceof VideoRoleData) &&
922                   !(role instanceof AudioRoleData)) )
923          return null;
924       else
925          return role;
926    }
927 
928    public String getFormat()            { return sFormat; }
929    public String getThumbLocation()     { return sThumbLocation; }
930    public String getThumbServer()       { return sThumbServer;   }
931    public String getThumbName()         { return sThumbName;     }
932    public String getThumbSize()         { return sThumbSize;     }
933    public String getPrimaryFormat()     { return sPrimaryFormat; }
934    public String getPrimaryWidth()      { return sPrimaryWidth;  }
935    public String getPrimaryHeight()     { return sPrimaryHeight; }
936    public String getPrimaryDPIX()       { return sPrimaryDPIX;   }
937    public String getPrimaryDPIY()       { return sPrimaryDPIY;   }
938    public String getPrimaryColorDepth() { return sPrimaryColorDepth; }
939    public String getPrimaryColorSpace() { return sPrimaryColorSpace; }
940    public String getPrimaryFileSize()   { return sPrimaryFileSize; }
941 } // ImageConvertService