001    /*
002     * $RCSfile: JDLHandler.java,v $ 
003     *
004     * Created on August 28, 2003, 13:28 AM
005     *
006     * This file is part of the STAR Scheduler.
007     * Copyright (c) 2002-2006 STAR Collaboration - Brookhaven National Laboratory
008     *
009     * STAR Scheduler is free software; you can redistribute it and/or modify
010     * it under the terms of the GNU General Public License as published by
011     * the Free Software Foundation; either version 2 of the License, or
012     * (at your option) any later version.
013     *
014     * STAR Scheduler is distributed in the hope that it will be useful,
015     * but WITHOUT ANY WARRANTY; without even the implied warranty of
016     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
017     * GNU General Public License for more details.
018     *
019     * You should have received a copy of the GNU General Public License
020     * along with STAR Scheduler; if not, write to the Free Software
021     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
022     */
023    package gov.bnl.star.offline.scheduler.request;
024    
025    import gov.bnl.star.offline.scheduler.*;
026    import gov.bnl.star.offline.scheduler.util.FilesystemToolkit;
027    import gov.bnl.star.offline.scheduler.util.sandbox.*;
028    import org.xml.sax.Attributes;
029    
030    import java.net.URL;
031    import java.net.URI;
032    import java.util.Arrays;
033    import java.util.List;
034    //import java.util.logging.Level;
035    import org.apache.log4j.Logger;
036    
037    
038    /**
039     * Reads a STAR scheduler XML request and creates a Request
040     * with the specified information.
041     *
042     * @author Gabriele Carcassi & Pavel Jakl & Levente Hajdu
043     * @version $Revision: 1.15 $ $Date: 2006/11/21 00:41:31 $
044     */
045    public class JDLHandler extends RequestHandler {
046    
047        static public Logger log = Logger.getLogger(RequestHandler.class.getName());
048        boolean readingCommand;
049        boolean readingFile;
050        private boolean startLimitDeprecationMessage = false;
051        private OutputFile currentOutput;
052        private SandboxPackage currentPackage;
053    
054        /**
055         * Parses an XML file according the STAR scheduler specification. More information
056         * about the specifications can be found in the STAR scheduler website.
057         *
058         * @param fileName the XML request file name
059         */
060        public JDLHandler(String fileName) {
061            super(fileName);
062        }
063    
064        String command = "";
065    
066        /**
067         * Parsing method. This method parses the XML file according to SAX specifications.
068         */
069        public void characters(char[] ch, int start, int length) {
070            
071            if (readingCommand) {
072                command += new String(ch, start, length);
073            }
074            
075            if(readingFile) packageFileElement(new String(ch, start, length));
076            
077        }
078    
079        private void flushCommandBuffer() {
080            
081            if (readingCommand) {
082                ((Request) requests.get(requests.size() - 1)).setCommand(command);
083                readingCommand = false;
084            }
085        }
086    
087        private void displayStartLimitDeprecationMessage() {
088            if (!startLimitDeprecationMessage) {
089                System.out.print("\nWARNING: The use of \"start\" and \"limit\" for catalog queries is deprecated.");
090                System.out.print("\nUse \"nFiles\" which will return only one copy per file.");
091                startLimitDeprecationMessage = true;
092            }
093        }
094    
095        private void catalogElement(Attributes attrs) {
096            Request req = ((Request) requests.get(requests.size() - 1));
097            List input = req.getInputList();
098            CatalogQuery query = new CatalogQuery(attrs.getValue("URL"));
099    
100            String nFiles = attrs.getValue("nFiles");
101    
102            if (nFiles != null) {
103                try {
104                    if (nFiles.equals("all")) {
105                        query.setNFiles(new Integer(-1));
106                    } else {
107                        query.setNFiles(new Integer(nFiles));
108                    }
109                } catch (NumberFormatException e) {
110                    log.fatal("Wrong argument for nFile attibute");
111                   
112                    throw new RuntimeException("Wrong argument for nFile attibute. Must be an integer and was: " +
113                            nFiles);
114                }
115            }
116    
117            if (attrs.getValue("limit") != null) {
118                try {
119                    displayStartLimitDeprecationMessage();
120                    query.setLimit(new Integer(attrs.getValue("limit")));
121                } catch (NumberFormatException e) {
122                    log.fatal("Wrong argument for a limit attibute");
123    
124                    throw new RuntimeException("Wrong argument for a limit attibute. Must be an integer and was: " +
125                            attrs.getValue("limit"));
126                }
127            }
128    
129            if (attrs.getValue("start") != null) {
130                try {
131                    displayStartLimitDeprecationMessage();
132                    query.setStart(new Integer(attrs.getValue("start")));
133                } catch (NumberFormatException e) {
134                    log.fatal("Wrong argument for a start attibute");
135                    throw new RuntimeException("Wrong argument for a start attibute. Must be an integer and was: " +
136                            attrs.getValue("limit"));
137                }
138            }
139    
140            if ((attrs.getValue("singleCopy") == null) ||
141                    (attrs.getValue("singleCopy").equals("true"))) {
142                query.setSingleCopy(true);
143            } else {
144                query.setSingleCopy(false);
145            }
146    
147            String preferStorage = attrs.getValue("preferStorage");
148    
149            if (preferStorage != null) {
150                List preferStorageAllowedValues = Arrays.asList(new String[]{
151                    "NFS", "local", "HPSS"
152                });
153    
154                if (preferStorageAllowedValues.contains(preferStorage)) {
155                    query.setPreferStorage(preferStorage);
156                } else {
157                    log.fatal("Wrong argument for a preferStorage attibute");
158                    throw new RuntimeException("Wrong argument for a preferStorage attibute.\n  Allowed values are: " +
159                            preferStorageAllowedValues + "\n  Specified value was: " +
160                            preferStorage);
161                }
162                // go through the requests and check if preferStorage is HPSS and fileListSyntax is xrootd
163                String fileListSyntax = req.getFileListType();
164                if ("HPSS".equals(preferStorage) && !"xrootd".equals(fileListSyntax)) {
165                    throw new RuntimeException("You have specified preferStorage as HPSS, but files from HPSS are accessible only with attribute fileListSyntax=\"xrootd\" !! \n"
166                            + "You have specified fileListSyntax as: " + fileListSyntax);
167                }
168            }
169            input.add(query);
170        }
171    
172        private void jobElement(String namespaceURI, String sName, String qName,
173                                Attributes attrs) {
174            // New process found in the job description
175            log.debug("Reading job");
176    
177            Request req = new Request(attrs.getValue("username"), null,
178                    attrs.getValue("name"), attrs.getValue("description"),
179                    xmlFileName);
180    
181            // Process maxFilesPerProcess
182            String maxFilesPerProcess = attrs.getValue("maxFilesPerProcess");
183    
184            if (maxFilesPerProcess != null) {
185                try {//this try is not really needed because it should have been validated before getting to this point.
186                    req.setResourceMax("FilesPerProcess", Integer.parseInt(maxFilesPerProcess));
187                    //System.out.println("MaxFilesPerProcess is set to = " + req.getMaxFilesPerProcess());//////////////////////////
188                } catch (NumberFormatException e) {
189                    log.fatal("maxFilesPerProcess must be an integer: " + maxFilesPerProcess, e);
190                    throw new RuntimeException("Illegal value for maxFilesPerProcess. Must be an integer and was: " +
191                            maxFilesPerProcess);
192                }
193            }
194            
195            // Process maxDiskSpace 
196            String maxStorageSpace = attrs.getValue("maxStorageSpace");
197            if (maxStorageSpace != null) {
198                req.setResourceMax("StorageSpace",
199                        Integer.parseInt(maxStorageSpace));
200                //System.out.println("maxStorageSpace = " + maxStorageSpace); //just for testing
201            }         
202            // Process minDiskSpace 
203            String minStorageSpace = attrs.getValue("minStorageSpace");
204            if (minStorageSpace != null) {
205                req.setResourceMin("StorageSpace",
206                        Integer.parseInt(minStorageSpace));
207                //System.out.println("minStorageSpace = " + minStorageSpace); //just for testing
208            }
209            
210            // Process maxMemory 
211            String maxMemory = attrs.getValue("maxMemory");
212            if (maxMemory != null) {
213    
214                req.setResourceMax("Memory", Integer.parseInt(maxMemory));
215                //System.out.println("maxStorageSpace = " + maxStorageSpace); //just for testing
216            }
217          
218            // Process minMemory 
219            String minMemory = attrs.getValue("minMemory");
220            if (minMemory != null) {
221    
222                req.setResourceMin("Memory", Integer.parseInt(minMemory));
223                //System.out.println("maxStorageSpace = " + maxStorageSpace); //just for testing
224            }
225            
226            
227            //minWallTime
228            String minWallTime = attrs.getValue("minWallTime");
229            if (minWallTime != null) {
230                req.setResourceMin("WallTime", Integer.parseInt(minWallTime));
231                //System.out.println(req.getMinWallTime());
232            }
233            
234            //maxWallTime
235            String maxWallTime = attrs.getValue("maxWallTime");
236            if (maxWallTime != null) {
237                req.setResourceMax("WallTime", Integer.parseInt(maxWallTime));
238                //System.out.println(req.getMaxWallTime());
239            }
240            
241    
242            // Process minFilesPerProcess
243            String minFilesPerProcess = attrs.getValue("minFilesPerProcess");
244            if (minFilesPerProcess != null) {
245                try {
246                    req.setResourceMin("FilesPerProcess", Integer.parseInt(minFilesPerProcess));
247                } catch (NumberFormatException e) {
248                    log.fatal("minFilesPerProcess must be an integer: " + minFilesPerProcess, e);
249                    throw new RuntimeException("Illegal value for minFilesPerProcess. Must be an integer and was: " + minFilesPerProcess);
250                }
251            } else
252                req.setResourceMin("FilesPerProcess", -1);
253            
254            // Process nProcesses
255            String nProcesses = attrs.getValue("nProcesses");
256            if (nProcesses != null) {
257                try {
258                    req.setNProcesses(Integer.parseInt(nProcesses));
259                } catch (NumberFormatException e) {
260                    log.fatal("nProcesses must be an integer: " + nProcesses, e);
261                    throw new RuntimeException("Illegal value for nProcesses. Must be an integer and was: " + nProcesses);
262                }
263            }
264    
265            if ("true".equals(attrs.getValue("simulation"))) {
266                System.out.println("\nThe \"simulation\" attribute is deprecated. It was confusiong since in STAR simulation has a specific meaning. ");
267                System.out.print("Use \"simulateSubmission\" instead. For this time, scheduling will continue anyway in simulation mode.");
268                req.setSimulation(true);
269            }
270    
271            if ("true".equals(attrs.getValue("simulateSubmission"))) {
272                req.setSimulation(true);
273            }
274    
275            if ("true".equals(attrs.getValue("mail"))) {
276                req.setMail(true);
277            }
278    
279            if (attrs.getValue("fileListSyntax") != null) {
280                req.setFileListType(attrs.getValue("fileListSyntax"));           
281            }
282    
283            if (attrs.getValue("filesPerHour") != null) {
284                try {
285                    req.setFilesPerHour(Double.parseDouble(attrs.getValue("filesPerHour")));
286                } catch (Exception ex) {
287                    log.fatal("filesPerHour not formatted correctly: " + attrs.getValue("filesPerHour"), ex);
288                    throw new RuntimeException("filesPerHour must be a number (ex. 23.5)");
289                }
290            }
291    
292            if (attrs.getValue("inputOrder") != null) {
293                req.prepareInputOrder(attrs.getValue("inputOrder"));
294                System.out.println("TEST: Input order " + req.getInputOrder());
295            }
296    
297            requests.add(req);
298        }
299    
300        private void fileElement(String namespaceURI, String sName, String qName, Attributes attrs) {
301            List input = ((Request) requests.get(requests.size() - 1)).getInputList();
302            
303    
304            if ((attrs.getValue("URL").indexOf('*') != -1) || (attrs.getValue("URL").indexOf('?') != -1)) {
305                // The URL contains a wildcard
306                if ((attrs.getValue("URL").startsWith("file:/")) && (!attrs.getValue("URL").startsWith("file://"))) {
307                    
308                    log.debug("Identified as individual file input: " + attrs.getValue("URL").substring(5));        
309                    String[] files = FilesystemToolkit.resolveWildcard(attrs.getValue("URL").substring(5));
310    
311                    try {
312                        for (int nFile = 0; nFile < files.length; nFile++) {
313                            URL file = new URL("file", null, files[nFile]);
314                            log.debug("Adding from wildcard: " + file);
315                            input.add(file);
316                        }
317                    } catch (Exception e) {
318                        log.debug( "Error while resolving wildcard: " + attrs.getValue("URL"), e);
319                        throw new RuntimeException("Error while resolving wildcard: " + attrs.getValue("URL"));
320                    }
321                } else {
322                    throw new RuntimeException("Can resolve wildcards only on local files: " + attrs.getValue("URL"));
323                }
324            } else {
325                // The URL doesn't contain a wildcard
326                try {
327                    input.add(new URL(attrs.getValue("URL")));
328                } catch (Exception e) {
329                    throw new RuntimeException("input URL isn't well specified.");
330                }
331            }
332        }
333    
334        private void fileListElement(String namespaceURI, String sName, String qName, Attributes attrs) {
335            List input = ((Request) requests.get(requests.size() - 1)).getInputList();
336            
337            //Only true if fileListSyntax="xrootd"
338            boolean alowXRootd = ((Request) requests.get(requests.size() - 1)).getFileListType().matches("xrootd");
339    
340            // The URL contains a wildcard
341            if ((attrs.getValue("URL").startsWith("filelist:/")) && (!attrs.getValue("URL").startsWith("filelist://"))) {
342                log.debug("Getting filelist: " + attrs.getValue("URL").substring(9));
343    
344                ///////////////////////    nfiles bug fix     ///////////////////////////
345                String nFiles = attrs.getValue("nFiles");
346                int nFilesInt = -1;
347                if (nFiles != null) {
348                    try {
349                        if (!nFiles.equals("all")) nFilesInt = new Integer(nFiles).intValue();
350                    } catch (NumberFormatException e) {
351                        log.fatal("Wrong argument for nFile attibute");
352                        throw new RuntimeException("Wrong argument for nFile attibute. Must be an integer and was: " + nFiles);
353                    }
354                }
355                /////////////////////////////////////////////////////////////////////////
356    
357                List files = FilesystemToolkit.retrieveFileListContents(attrs.getValue("URL").substring(9), nFilesInt);
358    
359                try {
360                    for (int nFile = 0; nFile < files.size(); nFile++) {
361    
362                        //Give the user some kind of error here look for the :/
363                        if (((String) files.get(nFile)).indexOf(":/") == -1){
364                            System.out.println("\nAll the files in the filelist must start with [Identifier]:/ \n example:  file:/mydir/myfile.root ");
365                        }
366    
367                        
368                        
369                        //Moved to request hendler
370                        //This line is needed to alow files with the "root:" protcal to be passed
371                        System.setProperty("java.protocol.handler.pkgs", "gov.bnl.star.offline.scheduler.util.protocol" );
372                        
373    
374                        URL file = new URL((String) files.get(nFile));
375                       
376    
377                        //Halt is the user is trying to input files in xrootd from and output it in paths or rootd  
378                        if((file.getProtocol().matches("root")) && (! alowXRootd) ){
379                            String falt = "\n\nYou are trying to input a filelist with xrootd file(s) in it  (example:"+ file +" ) , and then convent the syntax of the output filelist to \"" +((Request) requests.get(requests.size() - 1)).getFileListType() + "\" syntax. This is not possible because node information will be lost (SUMS can't convert LFN to PFN ). Please change your fileListSyntax in the job tag to xrootd or change your file lists syntax.\n\n";
380                            System.out.println(falt);
381                            throw new RuntimeException(falt);    
382                        }
383                              
384    
385                        log.debug("Adding from filelist: " + file);
386                        input.add(file);
387                    }
388                } catch (Exception e) {
389                    log.fatal( "Error while processing filelist : " + attrs.getValue("URL"), e);
390                    throw new RuntimeException("Error while processing filelist: " + attrs.getValue("URL"));
391                }
392            } else {
393                throw new RuntimeException("Can resolve wildcards only on local files: " + attrs.getValue("URL"));
394            }
395        }
396    
397    
398        private void stdinElement(String namespaceURI, String sName, String qName,
399                                  Attributes attrs) {
400            // Standard input for the current process
401            log.debug("Reading stdin");
402    
403            if (attrs.getValue("URL") != null) {
404                try {
405                    ((Request) requests.get(requests.size() - 1)).setStdIn(new URL(attrs.getValue("URL")));
406                } catch (Exception e) {
407                    throw new RuntimeException("Stdin URL isn't well specified.");
408                }
409            } else {
410                throw new RuntimeException("Stdin syntax not understood or not implemented.");
411            }
412        }
413    
414        private void stdoutElement(String namespaceURI, String sName, String qName,
415                                   Attributes attrs) {
416            // Standard output for the current process
417            log.debug("Reading stdout");
418            boolean urlNotSet = true;
419    
420            if (attrs.getValue("URL") != null) {
421                try {
422                    ((Request) requests.get(requests.size() - 1)).setStdOut(new URL(attrs.getValue("URL")));
423                    urlNotSet = false;
424                } catch (Exception e) {
425                    throw new RuntimeException("Stdout URL isn't well specified.");
426                } 
427            }     
428            if (attrs.getValue("discard") != null){
429                if (attrs.getValue("discard").equals("true")) {
430                    ((Request) requests.get(requests.size() - 1)).setStdOut(Request.discard); 
431                } else if( attrs.getValue("discard").equals("false")) {
432                    if(urlNotSet) throw new RuntimeException("If discard=\"false\" then the URL must be set for the stdout element.");
433                }else{
434                    throw new RuntimeException("Stdout syntax not understood or not implemented.");
435                }
436            }       
437        }
438    
439        private void stderrElement(String namespaceURI, String sName, String qName, Attributes attrs) {
440            // Standard error for the current process
441            log.debug("Reading stderr");
442            boolean urlNotSet = true;
443    
444            if (attrs.getValue("URL") != null) {
445                try {
446                    ((Request) requests.get(requests.size() - 1)).setStdErr(new URL(attrs.getValue("URL")));
447                    urlNotSet = false;
448                } catch (Exception e) {
449                    throw new RuntimeException("Stderr URL isn't well specified.");
450                }
451            }    
452                
453            
454            if (attrs.getValue("discard") != null){
455                
456                if (attrs.getValue("discard").equals("true")) {
457                    ((Request) requests.get(requests.size() - 1)).setStdErr(Request.discard);
458                }else if( attrs.getValue("discard").equals("false")) {
459                        if(urlNotSet) throw new RuntimeException("If discard=\"false\" then the URL must be set for the stderr element.");
460                }else{
461                    throw new RuntimeException("Stderr syntax not understood or not implemented.");
462                }
463            }
464            
465        }
466    
467        private void inputElement(String namespaceURI, String sName, String qName,
468                                  Attributes attrs) {
469            // Input file for the current process
470            log.debug("Reading input");
471    
472            if (attrs.getValue("URL") != null) {
473                if (attrs.getValue("URL").startsWith("catalog:")) {
474                    log.debug("Identified as catalog input  ");
475                    catalogElement(attrs);
476                } else if (attrs.getValue("URL").startsWith("filelist:")) {
477                    log.debug("Identified as filelist input");
478                    fileListElement(namespaceURI, sName, qName, attrs);
479                } else {
480                    log.debug("Identified as individual file input");
481                    fileElement(namespaceURI, sName, qName, attrs);
482                }
483            } else {
484                log.fatal("Could not identified input");
485                throw new RuntimeException("input syntax not understood or not implemented.");
486            }
487        }
488    
489        private void outputElement(String namespaceURI, String sName, String qName,
490                                   Attributes attrs) {
491            // Output file for the current process
492            log.debug("Reading output");
493    
494            List output = ((Request) requests.get(requests.size() - 1)).getOutputList();
495    
496            if ((attrs.getValue("fromScratch") != null)) {
497                OutputFile file = new OutputFile(attrs.getValue("fromScratch"),
498                        attrs.getValue("toURL"));
499                currentOutput = file;
500                output.add(file);
501            } else {
502                throw new RuntimeException("output syntax not understood or not implemented.");
503            }
504        }
505    
506        private void outputCopyActionElement(String namespaceURI, String sName, String qName,
507                                             Attributes attrs) {
508            if ((attrs.getValue("to") != null)) {
509    
510                int sleep = -1;
511                int retries = -1;
512    
513                if ((attrs.getValue("retries") != null)) {
514                    try { //try to recover the int from the retries attribute
515                        retries = java.lang.Integer.parseInt(attrs.getValue("retries"));
516                    } catch (Exception e) {
517                        throw new RuntimeException("The value of \"retries\" in the copy tag must be an integer\n", e);
518                    }
519                    if ((attrs.getValue("sleep") != null)) {
520                        try { //try to recover the int from the sleep attribute 
521                            sleep = java.lang.Integer.parseInt(attrs.getValue("sleep"));
522                        } catch (Exception e) {
523                            throw new RuntimeException("The value of \"sleep\" in the copy tag must be an integer\n", e);
524                        }
525                    }
526                }
527    
528                OutputCopyAction action = new OutputCopyAction(currentOutput.getActionList(),
529                        attrs.getValue("id"),
530                        attrs.getValue("referto"),
531                        attrs.getValue("to"),
532                        retries,
533                        sleep,
534                        attrs.getValue("Type"));
535                currentOutput.getActionList().add(action);
536            } else
537                throw new RuntimeException("copy must have a \"to\" attribute.");
538        }
539    
540        private void outputCopyRegisterElement(String namespaceURI, String sName, String qName,
541                                               Attributes attrs) {
542            if ((attrs.getValue("to") != null)) {
543    
544                int sleep = -1;
545                int retries = -1;
546    
547                if ((attrs.getValue("retries") != null)) {
548                    try { //try to recover the int from the retries attribute
549                        retries = java.lang.Integer.parseInt(attrs.getValue("retries"));
550                    } catch (Exception e) {
551                        throw new RuntimeException("The value of \"retries\" must be an integer\n", e);
552                    }
553                    if ((attrs.getValue("sleep") != null)) {
554                        try { //try to recover the int from the sleep attribute
555                            sleep = java.lang.Integer.parseInt(attrs.getValue("sleep"));
556                        } catch (Exception e) {
557                            throw new RuntimeException("The value of \"sleep\" must be an integer\n", e);
558                        }
559                    }
560                }
561    
562    
563                OutputRegisterAction action = new OutputRegisterAction(currentOutput.getActionList(),
564                        attrs.getValue("id"),
565                        attrs.getValue("referto"),
566                        attrs.getValue("to"),
567                        retries,
568                        sleep);
569                currentOutput.getActionList().add(action);
570            } else {
571                throw new RuntimeException("register tag must have a \"to\" attribute.");
572            }
573        }
574    
575    
576        private void outputLinkAction(String namespaceURI, String sName, String qName, Attributes attrs) {
577    
578            if ((attrs.getValue("to") != null)) {
579    
580                int sleep = -1;
581                int retries = -1;
582    
583                if ((attrs.getValue("retries") != null)) {
584                    try { //try to recover the int from the retries attribute
585                        retries = java.lang.Integer.parseInt(attrs.getValue("retries"));
586                    } catch (Exception e) {
587                        throw new RuntimeException("The value of \"retries\" must be an integer\n", e);
588                    }
589                    if ((attrs.getValue("sleep") != null)) {
590                        try { //try to recover the int from the sleep attribute
591                            sleep = java.lang.Integer.parseInt(attrs.getValue("sleep"));
592                        } catch (Exception e) {
593                            throw new RuntimeException("The value of \"sleep\" must be an integer\n", e);
594                        }
595                    }
596                }
597    
598                OutputLinkAction action = new OutputLinkAction(currentOutput.getActionList(),
599                        attrs.getValue("id"),
600                        attrs.getValue("referto"),
601                        attrs.getValue("to"),
602                        retries,
603                        sleep,
604                        attrs.getValue("kind"));
605    
606    
607                currentOutput.getActionList().add(action);
608            } else {
609                throw new RuntimeException("link must have a \"to\" attribute.");
610            }
611    
612        }
613        
614        
615          private void SandboxElement(String namespaceURI, String sName, String qName, Attributes attrs) {
616                 Request request = (Request) requests.get(requests.size() - 1);
617                 if(request.getSandbox()!= null){
618                     throw new RuntimeException("You can only have one sand box element.");
619                 }
620                 if ((attrs.getValue("installer") == null)){
621                     request.setSandbox(new LocalSandbox() );   
622                 }
623                 else if( attrs.getValue("installer").compareTo("ZIP") == 0 ){
624                     request.setSandbox(new ZipSandbox() );   
625                 }
626                 else if( attrs.getValue("installer").compareTo("PACMAN") == 0 ){
627                     request.setSandbox(new PackmanSandbox() );   
628                 }
629                 else {
630                     throw new RuntimeException("The sandox installer is unkown !!");
631                 }          
632          }
633          
634          
635           private void PackageElement(String namespaceURI, String sName, String qName, Attributes attrs) {
636                currentPackage = new SandboxPackage();
637                
638                Sandbox sandbox = ((Request) requests.get(requests.size() - 1)).getSandbox();
639                
640                if(sandbox == null){
641                    throw new RuntimeException("Could not make sandbox for Package");    
642                }
643                
644                if ((attrs.getValue("name") != null)) {
645                   currentPackage.setPackageName(attrs.getValue("name"));
646                }
647                if ((attrs.getValue("repository") != null)) {
648                    currentPackage.setRepository(attrs.getValue("repository"));
649                }
650                if ((attrs.getValue("installdir") != null)) {
651                    currentPackage.setInstalldir(attrs.getValue("installdir"));
652                }
653                if ((attrs.getValue("version") != null)) {
654                    currentPackage.setVersion(attrs.getValue("version"));
655                }
656                
657                sandbox.addPackage(currentPackage);
658           }
659           
660           
661           private void packageFileElement(String file) {
662               
663               
664               
665                if(file.matches("^file\\:((\\.{2,2}/)|(\\./.*/\\.\\./)|(\\./\\.\\./)).*$")){
666                    throw new RuntimeException("Sorry, you are not allowed to have a relative path in your sandbox that has a reference to a parent director, item \"" + file +"\".");
667                }
668                
669                
670                if(!file.matches("^file\\:.*$")){
671                    throw new RuntimeException("Files in the sandbox must be in the format of file:[path]\\[fileName]\n" +
672                        "Examples:\n" +
673                        "file:/bla/bla/myfile.root\n" +
674                        "file:./bla/bla/myfile.root\n" +
675                        "file:./*.root\n");
676                }
677    
678                
679                
680                
681               
682                try{   
683                   currentPackage.addFile(new URL(file));
684                } catch (Exception e) {
685                        throw new RuntimeException("the <File> </File> tag is not a URI. \n\n" +
686                            "Examples of valid sandbox file formats are:\n" +
687                            "file:/bla/bla/myfile.root\n" +
688                            "file:./bla/bla/myfile.root\n" +
689                            "file:./*.root\n", e);
690                
691                }
692                   readingFile = false; 
693           }
694        /**
695         * Parsing method. This method parses the XML file according to SAX specifications.
696         */
697        public void startElement(String namespaceURI, String sName, String qName, Attributes attrs) {
698            if (qName.equals("job")) {
699                jobElement(namespaceURI, sName, qName, attrs);
700            } else if (qName.equals("command")) {
701                readingCommand = true;
702            } else if (qName.equals("stdin")) {
703                stdinElement(namespaceURI, sName, qName, attrs);
704            } else if (qName.equals("stdout")) {
705                stdoutElement(namespaceURI, sName, qName, attrs);
706            } else if (qName.equals("stderr")) {
707                stderrElement(namespaceURI, sName, qName, attrs);
708            } else if (qName.equals("input")) {
709                inputElement(namespaceURI, sName, qName, attrs);
710            } else if (qName.equals("output")) {
711                outputElement(namespaceURI, sName, qName, attrs);
712            } else if ((currentOutput != null) && ("copy".equals(qName))) {
713                outputCopyActionElement(namespaceURI, sName, qName, attrs);
714            } else if ((currentOutput != null) && ("register".equals(qName))) {
715                outputCopyRegisterElement(namespaceURI, sName, qName, attrs);
716            } else if ((currentOutput != null) && ("link".equals(qName))) {
717                outputLinkAction(namespaceURI, sName, qName, attrs);
718            } else if (qName.equals("SandBox")) {
719                SandboxElement(namespaceURI, sName, qName, attrs);    
720            } else if (qName.equals("Package")) {   
721                PackageElement(namespaceURI, sName, qName, attrs);
722            } else if (qName.equals("File")) {  
723                readingFile = true;
724                
725                
726                
727                
728            } else {
729                throw new RuntimeException("Found element out of the specifications : " + qName);
730            }
731        }
732    
733        public void endElement(String uri, String localName, String qName) throws org.xml.sax.SAXException {
734            if ("command".equals(qName)) {
735                flushCommandBuffer();
736            }
737            if ("output".equals(qName)) {
738                currentOutput = null;
739            }
740        }
741    
742    }