001/*
002 * Copyright (c) 2003-2010 The Regents of the University of California.
003 * All rights reserved.
004 *
005 * '$Author: crawl $'
006 * '$Date: 2013-02-21 21:33:59 +0000 (Thu, 21 Feb 2013) $' 
007 * '$Revision: 31478 $'
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
030package org.kepler.objectmanager.repository;
031
032import java.io.File;
033import java.io.FileOutputStream;
034import java.io.InputStream;
035import java.util.ArrayList;
036import java.util.List;
037import java.util.Vector;
038import java.util.concurrent.atomic.AtomicBoolean;
039
040import org.apache.commons.logging.Log;
041import org.apache.commons.logging.LogFactory;
042import org.ecoinformatics.ecogrid.queryservice.resultset.ResultsetTypeRecord;
043import org.kepler.gui.GraphicalActorMetadata;
044import org.kepler.kar.karxml.KarXml;
045import org.kepler.objectmanager.cache.ActorCacheObject;
046import org.kepler.objectmanager.cache.CacheException;
047import org.kepler.objectmanager.cache.CacheObject;
048import org.kepler.objectmanager.lsid.KeplerLSID;
049
050import ptolemy.kernel.ComponentEntity;
051import ptolemy.kernel.util.NamedObj;
052import ptolemy.kernel.util.StringAttribute;
053/**
054 * This class represents a single result from a search of the ecogrid
055 * repository. If there are many results (as in a resultset), then multiple
056 * EcogridRepositoryResults can be put into an iterator.
057 * 
058 * @author Chad Berkley
059 */
060public class EcogridRepositoryResults {
061        private static final Log log = LogFactory.getLog(EcogridRepositoryResults.class.getName());
062        private static final boolean isDebugging = log.isDebugEnabled();
063        
064        private String docid;
065        private String name;
066        private KarXml.KarEntry karEntry;
067        private String lsid;
068        private String karLSID;
069        private Vector<String> semTypes;
070        private ComponentEntity component;
071        private CacheObject cachedComponent;
072        private AtomicBoolean isReady = new AtomicBoolean(false);
073        private AtomicBoolean hasException = new AtomicBoolean(false);
074        private String repositoryName;
075        private File karFile;
076        private Integer indexValue = null;
077        private org.kepler.objectmanager.repository.KARDownloader downloader;
078
079        public static List<EcogridRepositoryResults> parseKarXml(String docid,
080                        String repositoryName, int indexValue, boolean authenticate) throws RepositoryException {
081                //System.out
082                //              .println("EcogridRepositoryResults parseKarXml Parsing KAR XML: "
083                //                              + docid);
084                List<EcogridRepositoryResults> results = new ArrayList<EcogridRepositoryResults>();
085                try {
086                        RepositoryManager rm = RepositoryManager.getInstance();
087                        Repository rep = rm.getRepository(repositoryName);
088                        if (rep instanceof EcogridRepository) {
089                        } else {
090                                log.error("EcogridRepositoryResults is trying to search "
091                                                + "a non-Ecogrid Repository");
092                                return null;
093                        }
094                        EcogridRepository erep = (EcogridRepository) rep;
095                        InputStream is = erep.get(docid, authenticate);
096
097                        KarXml karXml = KarXml.of(is);
098                        String karLSID = karXml.getLsid();
099                        if (karXml != null) {
100                                karXml.setRepositoryName(repositoryName);
101                                for (KarXml.KarEntry entry : karXml.getKarEntries()) {
102                                        EcogridRepositoryResults ecogridResult = new EcogridRepositoryResults(
103                                                        entry, repositoryName, indexValue, karLSID);
104                                        ecogridResult.setDocId(docid);
105                                        results.add(ecogridResult);
106                                }
107                        }
108
109                } catch (Exception ex) {
110                        ex.printStackTrace();
111                }
112                return results;
113        }
114        
115        public EcogridRepositoryResults(String karLSID, String repositoryName, boolean authenticate) {
116                // Initialize just the karLsid and repositoryName variables. This is
117                // intended to be used just to cache the KAR to local storage.
118                this.karLSID = karLSID;
119                this.repositoryName = repositoryName;
120        }
121        
122        public EcogridRepositoryResults(KarXml.KarEntry karEntry, String repositoryName, 
123                        int indexValue, String karLSID) throws RepositoryException {
124                this.indexValue = indexValue;
125                this.karEntry = karEntry;
126                this.repositoryName = repositoryName;
127                this.karLSID = karLSID;
128                try {
129                        if (karEntry.getType().endsWith(".TypedCompositeActor")) {
130                                cachedComponent = new ActorCacheObject(karEntry.asInputStream());
131                        }
132                }
133                catch(CacheException ex) {
134                        log.error("Cache exception", ex);
135                }
136                name = karEntry.getName();
137                lsid = karEntry.getLsid();              
138                semTypes = new Vector<String>(karEntry.getSemanticTypes());
139        }
140
141        /**
142         * All EcogridRepositoryResults produced by a single call to parseKarXml()
143         * will be assigned the same index value so they can later be put under a
144         * common KAR file. The index value is guaranteed to be unique to the
145         * contents of one KAR file only within the results produced by a single
146         * call to EcogridRepository.search(). Subsequent calls *will* produce
147         * colliding values.
148         * @return The index value shared by all EcogridRepositoryResults instances
149         * generated from the same KAR file. Calls to this method by
150         * EcogridRepositoryResults instances that were not generated through
151         * parsing a KAR XML file will produce null. 
152         */
153        public Integer getIndexValue() {
154                return indexValue;
155        }
156        
157        public KarXml.KarEntry getKarEntry() {
158                return karEntry;
159        }
160        /**
161         * default constructor
162         */
163        public EcogridRepositoryResults(ResultsetTypeRecord record,
164                        String repositoryName, boolean authenticate) throws RepositoryException {
165                this.repositoryName = repositoryName;
166                try {
167                        semTypes = new Vector<String>();
168                        docid = record.getIdentifier();
169                        // get the document from the repository and parse it into an
170                        // actormetadata
171                        // object
172                        
173                        RepositoryManager rm = RepositoryManager.getInstance();
174                        Repository rep = rm.getRepository(repositoryName);
175                        if (rep instanceof EcogridRepository) {
176                        } else {
177                                log.error("EcogridRepositoryResults is trying to search "
178                                                + "a non-Ecogrid Repository");
179                                return;
180                        }
181                        
182                        EcogridRepository erep = (EcogridRepository) rep;
183                        
184                        InputStream is = erep.get(docid, authenticate);
185                        
186                        GraphicalActorMetadata gam = new GraphicalActorMetadata(is);
187                        NamedObj obj = gam.getActorAsNamedObj(null);
188                        
189                        component = (ComponentEntity) obj;
190                        name = gam.getName();
191                        lsid = gam.getId();
192                        
193                        StringAttribute sa = (StringAttribute) obj.getAttribute("karId");
194                        if (sa != null) {
195                                karLSID = sa.getExpression();
196
197                                if (isDebugging) {
198                                        log.debug("karLSID: " + karLSID);
199                                }
200                                // possibly here, kick off a thread to start downloading the kar
201                                // files into
202                                // the classpath
203                        }
204
205                        semTypes = gam.getSemanticTypes();
206                } catch (Exception e) {
207                        // e.printStackTrace();
208                        throw new RepositoryException("Error getting actor metadata for "
209                                        + "resultset document: " + e.getMessage());
210                }
211        }
212
213        /**
214         * download the kar file and get it ready to be imported into the local
215         * system.
216         */
217        public File cacheKAR(boolean authenticate) throws RepositoryException {
218                // break off a new thread
219                // run the download in that thread
220                // set isReady to true;
221                (new KARDownloader(downloader, authenticate)).start();
222                while (!isReady()) {
223                } // wait for the download. this can be done away with when the
224                        // interface
225                // is fixed to download upon drag n drop
226
227                if (hasException()) {
228                        throw new RepositoryException("Error caching the kar file for the "
229                                        + "component " + lsid);
230                }
231                return karFile;
232        }
233
234        /**
235         * returns true of the kar file from this result is ready for use
236         */
237        public boolean isReady() {
238                return isReady.get();
239        }
240
241        /**
242         * returns true if the kar caching thread has thrown an exception
243         */
244        public boolean hasException() {
245                return hasException.get();
246        }
247
248        /**
249         * return a string rep of this object
250         */
251        public String toString() {
252                StringBuffer sb = new StringBuffer();
253                sb.append("{name: " + name);
254                sb.append(", docid: " + docid);
255                sb.append(", lsid: " + lsid);
256                sb.append(", karId: " + karLSID);
257                sb.append(", semanticTypes: " + semTypes.toString());
258                sb.append("}");
259                return sb.toString();
260        }
261
262        /**
263         * return the docid of the result
264         */
265        public String getDocid() {
266                return docid;
267        }
268
269        /**
270         * return the name of the component
271         */
272        public String getName() {
273                return name;
274        }
275
276        /**
277         * return the lsid (entityId) of the component
278         */
279        public String getLSID() {
280                return lsid;
281        }
282
283        /**
284         * return the lsid of the kar file associated with this component
285         */
286        public String getKarLSID() {
287                return karLSID;
288        }
289
290        /**
291         * return any semantic types associated with this component
292         */
293        public Vector<String> getSemanticTypes() {
294                return semTypes;
295        }
296        
297        public CacheObject getCacheObject() {
298                return cachedComponent;
299        }
300
301        /**
302         * return the instantiated
303         */
304        public ComponentEntity getComponent() {
305                return component;
306        }
307        
308        /**
309         * Set the docid (kar xml id)
310         * @param docid
311         */
312        public void setDocId(String docid)
313        {
314          this.docid =docid;
315        }
316
317        public void setDownloader(org.kepler.objectmanager.repository.KARDownloader downloader) {
318                this.downloader = downloader;
319        }
320
321        /**
322         * a class to download the kar file in a new thread.
323         */
324        private class KARDownloader extends Thread {
325                // location to download the kar file to
326                String tempPath = org.kepler.objectmanager.cache.CacheManager.tmpPath;
327                private org.kepler.objectmanager.repository.KARDownloader downloader;
328
329                private boolean authenticate = false;
330                
331                public void setAuthenticate(boolean authenticate){
332                        this.authenticate = authenticate;
333                }
334                public boolean getAuthenticate(){
335                        return authenticate;
336                }
337                
338                public KARDownloader() {
339                        super();
340                }
341                
342                public KARDownloader(org.kepler.objectmanager.repository.KARDownloader downloader, boolean authenticate) {
343                        this();
344                        this.downloader = downloader;
345                        this.authenticate = authenticate;
346                }
347
348                /**
349                 * get the kar and download it to the cache
350                 */
351                public void run() {
352                        try {
353                                if (karLSID == null){
354                                        System.out.println("EcogridRepositoryResults KARDownloader.run() ERROR karLSID is null");
355                                }
356                                KeplerLSID karlsid = new KeplerLSID(karLSID);
357                                String karSavePath = this.downloader.getKarPath();
358                                if (karSavePath == null) {
359                                        karSavePath = tempPath;
360                                }
361                                String karFilename = this.downloader.getKarName();
362                                if (karFilename == null) {
363                                        karFilename = karlsid.createFilename() + ".kar";
364                                        System.out.println("No KAR name found in XML, using LSID for filename instead:"+karFilename);
365                                }
366                                File karPath = new File(karSavePath);
367                                karFile = new File(karPath, karFilename);
368                                karPath.mkdirs();
369                                FileOutputStream fos = null;
370                                try {
371                                        fos = new FileOutputStream(karFile);
372                                        EcogridRepository repository = (EcogridRepository) RepositoryManager
373                                                        .getInstance().getRepository(repositoryName);
374                                        InputStream is = repository.get(karlsid, authenticate);
375                                        byte[] b = new byte[1024];
376                                        int numread = is.read(b, 0, 1024);
377                                        downloader.updateDownloadProgress(numread);
378                                        while (numread != -1) {
379                                                fos.write(b, 0, numread);
380                                                numread = is.read(b, 0, 1024);
381                                                downloader.updateDownloadProgress(numread);
382                                        }
383                                        fos.flush();
384                                        isReady.set(true);
385                                } finally {
386                                        if(fos != null) {
387                                                fos.close();
388                                        }
389                                }
390                        } catch (Exception e) {
391                                System.out.println("Error downloading kar file: "
392                                                + e.getMessage());
393                                // e.printStackTrace();
394                                hasException.set(true);
395                                isReady.set(true);
396                        }
397                }
398        }
399}