001/*
002 * Copyright (c) 2010 The Regents of the University of California.
003 * All rights reserved.
004 *
005 * '$Author: crawl $'
006 * '$Date: 2012-11-26 22:23:27 +0000 (Mon, 26 Nov 2012) $' 
007 * '$Revision: 31127 $'
008 * 
009 * Permission is hereby granted, without written agreement and without
010 * license or royalty fees, to use, copy, modify, and distribute this
011 * software and its documentation for any purpose, provided that the above
012 * copyright notice and the following two paragraphs appear in all copies
013 * of this software.
014 *
015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
019 * SUCH DAMAGE.
020 *
021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
026 * ENHANCEMENTS, OR MODIFICATIONS.
027 *
028 */
029
030/**
031 * 
032 */
033package org.kepler.kar.handlers;
034
035import java.io.ByteArrayInputStream;
036import java.io.File;
037import java.io.InputStream;
038import java.util.HashMap;
039import java.util.Hashtable;
040import java.util.Iterator;
041import java.util.List;
042import java.util.Map;
043import java.util.Vector;
044
045import org.apache.commons.logging.Log;
046import org.apache.commons.logging.LogFactory;
047import org.kepler.configuration.ConfigurationManager;
048import org.kepler.configuration.ConfigurationProperty;
049import org.kepler.kar.KAREntry;
050import org.kepler.kar.KAREntryHandler;
051import org.kepler.kar.KAREntryHandlerFactory;
052import org.kepler.kar.KARFile;
053import org.kepler.objectmanager.cache.CacheObject;
054import org.kepler.objectmanager.lsid.KeplerLSID;
055import org.kepler.objectmanager.lsid.LSIDGenerator;
056import org.kepler.provenance.Queryable;
057import org.kepler.reporting.rio.ReportInstance;
058import org.kepler.reporting.rio.fop.ReportRenderer;
059import org.kepler.reporting.rio.util.ProvenanceUtil;
060import org.kepler.util.WorkflowRun;
061import org.kepler.workflowrunmanager.WorkflowRunManager;
062import org.kepler.workflowrunmanager.WorkflowRunManagerManager;
063
064import ptolemy.actor.gui.TableauFrame;
065import ptolemy.data.StringToken;
066import ptolemy.data.Token;
067import ptolemy.kernel.util.IllegalActionException;
068import ptolemy.kernel.util.NameDuplicationException;
069import ptolemy.kernel.util.NamedObj;
070
071/**
072 * @author Ben Leinfelder
073 * 
074 */
075public class ReportInstanceKAREntryHandler implements KAREntryHandler {
076
077        private static final Log log = LogFactory.getLog(ReportInstanceKAREntryHandler.class.getName());
078
079        public ReportInstanceKAREntryHandler() {
080        }
081
082        /**
083         * Method for backwards compatibility with KAR version 1.0 KAR version 2.0
084         * uses the binary class name as the type.
085         * 
086         * @see org.kepler.kar.KAREntryHandler#getTypeName()
087         */
088        public String getTypeName() {
089                return ReportInstance.class.getName();
090        }
091
092        public boolean handlesType(String typeName) {
093                // currently we do not open these types
094//              if (typeName.equals(ReportInstance.class.getName())) {
095//                      return true;
096//              }
097                return false;
098        }
099
100        /*
101         * (non-Javadoc)
102         * 
103         * @see org.kepler.kar.KAREntryHandler#initialize()
104         */
105        public void initialize() {
106                log.debug("initialize()");
107        }
108
109        public boolean open(KARFile karFile, KAREntry entry, TableauFrame tableauFrame) throws Exception {
110                return false;
111        }
112        
113        /*
114         * (non-Javadoc)
115         * 
116         * @see org.kepler.kar.KAREntryHandler#open(java.util.jar.JarEntry)
117         */
118        public CacheObject cache(KARFile karFile, KAREntry entry) throws Exception {
119                log.debug("open(" + karFile.toString() + "," + entry.toString() + ")");
120                
121                // Not doing anything with the instance docs currently
122                
123                // look up the LSID for the entry
124                ///KeplerLSID lsid = entry.getLSID();
125                                
126                return null;
127
128        }
129
130        /*
131         * (non-Javadoc)
132         * 
133         * @see
134         * org.kepler.kar.KAREntryHandler#save(org.kepler.objectmanager.lsid.KeplerLSID
135         * )
136         */
137        public Hashtable<KAREntry, InputStream> save(Vector<KeplerLSID> lsids, KeplerLSID karLsid,
138                        TableauFrame tableauFrame)
139                throws Exception {
140                
141                Hashtable<KAREntry, InputStream> items = new Hashtable<KAREntry, InputStream>();
142
143                for (KeplerLSID lsid : lsids) {
144                
145                        // refactored to get run from WRM instead of OM on Nov03 2010.
146                        // this isn't necessary, but maybe better to rely on OM less.
147                        // determine what we are saving, and call the appropriate method
148                        //NamedObj nObj = ObjectManager.getInstance().getObjectRevision(lsid);
149                        //if (nObj instanceof WorkflowRun) {
150                        //      System.out.println("ReportInstanceKAREntryHandler save got WorkflowRun nObj from OM for:"+lsid);
151                        //      NamedObjId noi = ObjectManager.getIdAttributeFor(nObj);
152                        //      items.putAll(saveReportInstanceForWorkflowRun(noi.getId(), karLsid, tableauFrame));
153                        //} else {
154                        //      //something else?
155                        //}
156                        
157                        WorkflowRunManagerManager wrmm = WorkflowRunManagerManager.getInstance();
158                        WorkflowRunManager wrm = wrmm.getWRM(tableauFrame);
159                        WorkflowRun run = wrm.getRun(lsid);
160                        if (run != null){
161                                items.putAll(saveReportInstanceForWorkflowRun(run, karLsid, tableauFrame));
162                        }
163                }
164                
165                return items;
166                
167        }
168
169        private Hashtable<KAREntry, InputStream> saveReportInstanceForWorkflowRun(WorkflowRun run, 
170                        KeplerLSID karLsid, TableauFrame tableauFrame) throws Exception {
171                
172                Hashtable<KAREntry, InputStream> items = new Hashtable<KAREntry, InputStream>();
173        
174                /// No longer using OM here, Nov 03, 2010
175                // Look up the WorkflowRun for the given LSID
176                //WorkflowRun run = null;
177                //try{
178                        //TODO make sure this is ok with highest:
179                //      run = (WorkflowRun) ObjectManager.getInstance().getHighestObjectRevision(lsid);
180                //}
181                //catch (Exception e){
182                //      log.warn("lsid does not represent WorkflowRun: " + e.getMessage());
183                //      return null;
184                //}
185                if (run == null) {
186                        log.debug("WorkflowRun is NULL, returning null");
187                        //log.debug("WorkflowRun save("+lsid+"): WARN: no object could be found for lsid: " + lsid);
188                        //System.out.println("ReportInstanceKAREntryHandler saveReportInstanceForWorkflowRun couldnt" +
189                        //              " get run from OM using lsid:"+lsid);
190                        return null;
191                }
192                
193                // Get a queryable for the workflow that ran
194                Queryable queryable = null;
195                try {
196                        queryable = ProvenanceUtil.getQueryable(run.getWorkflowLSID(), tableauFrame);
197                } catch (Exception e3) {
198                        log.error("could not find queryable for the workflow: " + run.getWorkflowLSID());
199                        e3.printStackTrace();
200                }
201                
202                // Get the report instance from provenance
203                ReportInstance reportInstance = null;
204                byte[] rioXML = null;
205                Map<String, String> metadataMap = new HashMap<String, String>();
206                metadataMap.put("type", ReportInstance.class.getName());
207                List<byte[]> dataList = null;
208                try {
209                        dataList = queryable.getAssociatedDataForExecution(
210                                                        run.getExecId(), 
211                                                        metadataMap, 
212                                                        false);
213                        if (dataList != null && !dataList.isEmpty()) {
214                                rioXML = dataList.get(0);
215                                // only constructing this to get the instance LSID
216                                reportInstance = (ReportInstance) ReportRenderer.convertXML2Report(new ByteArrayInputStream(rioXML));
217                                ///don't use ReportInstance(rl) constructor here, or you'll later get a serialization error
218                                ///ReportLayout rl = ReportRenderer.convertXML2Report(new ByteArrayInputStream(rioXML));
219                                ///reportInstance  = new ReportInstance(rl);
220                        }
221                } catch (Exception e2) {
222                        log.error("error looking up report instance XML: " + e2.getMessage());
223                        e2.printStackTrace();
224                }
225
226                if (reportInstance == null) {
227                        return items;
228                }
229                
230                // Add the RIO XML
231                log.debug("Adding ReportInstance: " + reportInstance);
232                KAREntry entryRIO = new KAREntry("RIO." + run.getExecId() + ".xml");
233                entryRIO.addAttribute("lsid", reportInstance.getLsid().toString());
234                entryRIO.addAttribute("type", ReportInstance.class.getName());
235                entryRIO.addLsidDependency(reportInstance.getWorkflowLSID());
236                entryRIO.addLsidDependency(run.getExecLSID());
237                
238                // promote configured fields from the RIO to the KAR entry
239                Map reportMapping = getReportMapping();
240                Iterator mappingIter = reportMapping.keySet().iterator();
241                while (mappingIter.hasNext()) {
242                        String itemName = (String) mappingIter.next();
243                        String attrName =  (String) reportMapping.get(itemName);
244                        // lookup the value for that name
245                        Token reportToken = reportInstance.lookupValue(itemName);
246                        if (reportToken != null && reportToken instanceof StringToken) {
247                                String attrValue = ((StringToken)reportToken).stringValue();
248                                try {
249                                        entryRIO.addAttribute(attrName, attrValue);
250                                } catch (Exception e) {
251                                        log.error("could not add reporting attribute to RIO entry: " + e.getMessage());
252                                        e.printStackTrace();
253                                }
254                        }
255                }
256                
257                try {
258                        items.put(entryRIO, new ByteArrayInputStream(rioXML));
259                } catch (Exception e1) {
260                        log.error("error adding RIO XML entry: " + e1.getMessage());
261                        e1.printStackTrace();
262                }
263                
264                // Get the PDF
265                byte[] rioPDF = null;
266                Map<String, String> metadataMapPDF = new HashMap<String, String>();
267                metadataMapPDF.put("type", File.class.getName());
268                List<byte[]> dataListPDF;
269                try {
270                        dataListPDF = queryable.getAssociatedDataForExecution(
271                                                        run.getExecId(), 
272                                                        metadataMapPDF, 
273                                                        false);
274                        if (dataListPDF != null && !dataListPDF.isEmpty()) {
275                                rioPDF = dataListPDF.get(0);
276                        }
277                } catch (Exception e2) {
278                        log.error("error looking up report instance PDF: " + e2.getMessage());
279                        e2.printStackTrace();
280                }
281                
282                // Add the PDF
283                log.debug("Adding PDF: ");
284                KAREntry entryPDF = new KAREntry("RIO." + run.getExecId() + ".pdf");
285                try {
286                        // TODO: is unregistered LSID okay for PDFs?
287                        KeplerLSID pdfLsid = LSIDGenerator.getInstance().getNewLSID();
288                        entryPDF.addAttribute("lsid", pdfLsid.toString());
289                        entryPDF.addAttribute("type", File.class.getName());
290                        entryPDF.addLsidDependency(run.getExecLSID());
291                        items.put(entryPDF, new ByteArrayInputStream(rioPDF));
292                } catch (Exception e1) {
293                        log.error("error adding RIO PDF entry: " + e1.getMessage());
294                        e1.printStackTrace();
295                }    
296                
297                return items;
298        }
299        
300        private static Map getReportMapping() {
301                
302                Map<String, String> reportMap = new HashMap<String, String>();
303                ConfigurationProperty reportingProperty = 
304                        ConfigurationManager.getInstance().getProperty(ConfigurationManager.getModule("reporting"));
305                List<ConfigurationProperty> mappings = ConfigurationProperty.getProperties(reportingProperty, "reporting.reportMapping", true);
306                for (ConfigurationProperty mapping: mappings) {
307                        String key = mapping.getProperty("itemName").getValue();
308                        String value = mapping.getProperty("metadataName").getValue();
309                        reportMap.put(key, value);
310                }
311                return reportMap;
312        }
313
314        /**
315         * A factory that creates a KAREntryHandler object.
316         * 
317         *@author aaron
318         */
319        public static class Factory extends KAREntryHandlerFactory {
320                /**
321                 * Create a factory with the given name and container.
322                 * 
323                 *@param container
324                 *            The container.
325                 *@param name
326                 *            The name of the entity.
327                 *@exception IllegalActionException
328                 *                If the container is incompatible with this attribute.
329                 *@exception NameDuplicationException
330                 *                If the name coincides with an attribute already in the
331                 *                container.
332                 */
333                public Factory(NamedObj container, String name)
334                                throws IllegalActionException, NameDuplicationException {
335                        super(container, name);
336                }
337
338                /**
339                 * Create a KAREntryHandler
340                 * 
341                 * @return A new KAREntryHandler that handles Reports
342                 */
343                public KAREntryHandler createKAREntryHandler() {
344                        log.debug("createKAREntryHandler()");
345                        ReportInstanceKAREntryHandler rikeh = new ReportInstanceKAREntryHandler();
346                        return rikeh;
347                }
348        }
349
350}