001/*
002 * Copyright (c) 2004-2010 The Regents of the University of California.
003 * All rights reserved.
004 *
005 * '$Author: barseghian $'
006 * '$Date: 2011-11-11 01:31:50 +0000 (Fri, 11 Nov 2011) $' 
007 * '$Revision: 28928 $'
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.ecoinformatics.seek.datasource.eml.eml2;
031
032import java.io.IOException;
033import java.util.Collections;
034import java.util.Hashtable;
035import java.util.List;
036import java.util.Vector;
037
038import org.apache.commons.logging.Log;
039import org.apache.commons.logging.LogFactory;
040import org.ecoinformatics.ecogrid.queryservice.query.QueryType;
041import org.ecoinformatics.ecogrid.queryservice.resultset.ResultsetType;
042import org.ecoinformatics.ecogrid.queryservice.resultset.ResultsetTypeRecord;
043import org.ecoinformatics.ecogrid.queryservice.resultset.ResultsetTypeRecordReturnField;
044import org.ecoinformatics.ecogrid.queryservice.resultset.ResultsetTypeResultsetMetadata;
045import org.ecoinformatics.ecogrid.queryservice.resultset.ResultsetTypeResultsetMetadataNamespace;
046import org.ecoinformatics.ecogrid.queryservice.resultset.ResultsetTypeResultsetMetadataRecordStructure;
047import org.ecoinformatics.ecogrid.queryservice.resultset.ResultsetTypeResultsetMetadataRecordStructureReturnField;
048import org.ecoinformatics.seek.ecogrid.MetadataSpecificationInterface;
049import org.ecoinformatics.seek.ecogrid.exception.EcoGridException;
050import org.ecoinformatics.seek.ecogrid.exception.InvalidEcogridQueryException;
051import org.ecoinformatics.seek.ecogrid.quicksearch.ResultRecord;
052import org.ecoinformatics.seek.ecogrid.quicksearch.SearchQueryGenerator;
053import org.ecoinformatics.seek.ecogrid.quicksearch.SortableResultRecord;
054import org.ecoinformatics.seek.ecogrid.quicksearch.SortableResultRecordComparator;
055import org.kepler.configuration.ConfigurationManager;
056import org.kepler.configuration.ConfigurationProperty;
057import org.kepler.kar.KARCacheContent;
058import org.kepler.kar.KARCacheManager;
059import org.kepler.moml.NamedObjId;
060import org.kepler.objectmanager.lsid.KeplerLSID;
061import org.xml.sax.SAXException;
062
063import ptolemy.kernel.CompositeEntity;
064import ptolemy.kernel.util.IllegalActionException;
065import ptolemy.kernel.util.NameDuplicationException;
066
067/**
068 * This class is a plugin for eml200 namespace to transfer query group to
069 * ecogrid query type. It also provide a method to create quick search query
070 * 
071 * @author Jing Tao
072 */
073
074public class EML2MetadataSpecification extends MetadataSpecificationInterface {
075        public static final String EML200NAMESPACE = "eml://ecoinformatics.org/eml-2.0.0";
076        private static final int NAMESPACEARRAYLENGTH = 1;
077        private static final String OPERATOR = "LIKE";
078        private static final String FILERFIELD = "filerField";
079        private static final String UNKNOWNTITLE = "unknownTitle";
080        private static final String REPLACE = "#value#";
081        private static final String QUERYID = "eml200-quick-search-query";
082
083        private int _numResults = 0;
084        protected String namespace = null;
085        protected String queryId = null;
086
087        protected final static Log log;
088        protected final static boolean isDebugging;
089        static {
090                log = LogFactory
091                                .getLog("org.ecoinformatics.seek.ecogrid.EML2MetadataSpecification");
092                isDebugging = log.isDebugEnabled();
093        }
094
095        // private String recordTitle = null;
096        // private Vector entityName = null;
097
098        /**
099         * Default constructor
100         */
101        public EML2MetadataSpecification() {
102                namespace = EML200NAMESPACE;
103                queryId = QUERYID;
104        }// Eml200EcoGridQueryTransfer
105
106        /**
107         * Method to create a quick query search
108         * 
109         * @param value
110         *            String
111         * @return QueryType
112         */
113        public QueryType getQuickSearchEcoGridQuery(String value)
114                        throws InvalidEcogridQueryException {
115                Hashtable replaceMapping = new Hashtable();
116                replaceMapping.put(REPLACE, value);
117                SearchQueryGenerator eml200QueryGenerator = new SearchQueryGenerator(
118                                queryId, replaceMapping);
119                QueryType ecogridQuery = eml200QueryGenerator.getQuery();
120                return ecogridQuery;
121
122        }// getQuickSearchEcoGridQuery
123
124        /**
125         * Method to create a ecogrid query
126         * 
127         * @return QueryType
128         */
129        public QueryType getEcoGridQuery() {
130                QueryType ecogridQuery = null;
131                return ecogridQuery;
132        }// getEcoGridQuery
133
134        /**
135         * This method will transfer ResultsetType java object to array of
136         * ResultRecord java object. The ResultRecord object can be shown in kepler.
137         * If the results is null or there is no record in the result, null will be
138         * return
139         * 
140         * @param ResultsetType
141         *            results the result need to be transform
142         * @param String
143         *            endpoints the search end point
144         * @return ResultRecord[] the resultrecord need be returned.
145         */
146        public ResultRecord[] transformResultset(ResultsetType results,
147                        String endpoint, CompositeEntity container) throws SAXException,
148                        IOException, EcoGridException, NameDuplicationException,
149                        IllegalActionException {
150                Eml200DataSource[] resultRecordArray = null;
151                if (results == null) {
152                        return resultRecordArray;
153                }
154
155                // get titlstring and entity name string from configure file
156                String titleReturnFieldString = null;
157                String entityReturnFieldString = null;
158                // xpath for config file
159                String titlePath = "//" + ECOGRIDPATH + "/" + RETURNFIELDTYPELIST + "/"
160                                + RETURNFIELD + "[@" + NAMESPACE + "='" + namespace + "' and @"
161                                + RETURNFIELDTYPE + "='" + RETURNFIELDTITLE + "']";
162        
163                String entityPath = "//" + ECOGRIDPATH + "/" + RETURNFIELDTYPELIST
164                                + "/" + RETURNFIELD + "[@" + NAMESPACE + "='" + namespace
165                                + "' and @" + RETURNFIELDTYPE + "='" + RETURNFIELDENTITY + "']";
166        
167                List titlePathList = null;
168                List entityPathList = null;
169    
170    //get the specific configuration we want
171    ConfigurationProperty ecogridProperty = ConfigurationManager.getInstance().getProperty(ConfigurationManager.getModule("ecogrid"));
172    ConfigurationProperty returnFieldTypeList = ecogridProperty.getProperty("returnFieldTypeList");
173    //findthe namespace properties
174    List returnFieldTypeNamespaceList = returnFieldTypeList.findProperties(NAMESPACE, namespace, true  );
175    //find the properties out of the correct namespace properties that also have the correct returnfieldtype
176    titlePathList = ConfigurationProperty.findProperties(returnFieldTypeNamespaceList, RETURNFIELDTYPE, RETURNFIELDTITLE, false);
177    //get the value list for the properties
178    titlePathList = ConfigurationProperty.getValueList(titlePathList, "value", true);
179        
180                if (titlePathList.isEmpty()) {
181                        log
182                                        .debug("Couldn't get title from config Eml200EcoGridQueryTransfer.transformResultset");
183                        throw new EcoGridException(
184                                        "Couldn't get title returnfield from config");
185                }
186
187    entityPathList = ConfigurationProperty.findProperties(returnFieldTypeNamespaceList, RETURNFIELDTYPE, RETURNFIELDENTITY, false);
188    //get the value list for the properties
189    entityPathList = ConfigurationProperty.getValueList(entityPathList, "value", true);
190    
191                if (entityPathList.isEmpty()) {
192                        log
193                                        .debug("Couldn't get entity returnfield from config Eml200EcoGridQueryTransfer.transformResultset");
194                        throw new EcoGridException(
195                                        "Couldn't get entity returnfield from config");
196                }
197                // only choose the first one in vector as title returnfied or
198                // entityreturn
199                // field
200                titleReturnFieldString = (String) titlePathList.get(0);
201                entityReturnFieldString = (String) entityPathList.get(0);
202
203                // transfer ResultType to a vector of eml2resultsetItem and
204                // sorted the vector
205                Vector resultsetItemList = transformResultsetType(results,
206                                titleReturnFieldString, entityReturnFieldString);
207                // transfer the sored vector (contains eml2resultsetitem object to an
208                // array
209                // of ResultRecord
210                int arraySize = resultsetItemList.size();
211                _numResults = arraySize;
212
213                resultRecordArray = new Eml200DataSource[arraySize];
214                Hashtable titleList = new Hashtable();// This hashtable is for keeping
215                                                                                                // track
216                // if there is a duplicate title
217                
218                KeplerLSID EML200ActorLSID = null;
219                for (int i = 0; i < arraySize; i++) {
220                        try {
221                                SortableResultRecord source = (SortableResultRecord) resultsetItemList
222                                                .elementAt(i);
223                                String title = source.getTitle();
224                                log.debug("The title is " + title);
225                                String id = source.getId();
226                                log.debug("The id is " + id);
227                                Vector entityList = source.getEntityList();
228                                // if couldn't find id, skip this record
229                                if (id == null || id.trim().equals("")) {
230                                        continue;
231                                }
232
233                                // if couldn't find title, assign a one to it -- <j>
234                                if (title == null || title.trim().equals("")) {
235                                        title = "<" + i + ">";
236                                }
237                                if (titleList.containsKey(title)) {
238                                        title = title + " " + i;
239                                }
240                                //make it unique in the result tree
241                                if (container.getEntity(title) != null) {
242                                        String hint = "another service";
243                                        if (endpoint.lastIndexOf("/") > -1) {
244                                                hint = endpoint.substring(endpoint.lastIndexOf("/") + 1);
245                                        }       
246                                        title = title + " (" + hint  + ")";
247                                }
248                                titleList.put(title, title);
249                                Eml200DataSource newRecord = new Eml200DataSource(container, title);
250                                newRecord.setRecordId(id);
251                                newRecord.setEndpoint(endpoint);
252                                newRecord.setNamespace(namespace);
253                                for (int j = 0; j < entityList.size(); j++) {
254                                        String entityNameString = (String) entityList.elementAt(j);
255                                        log.debug("The entiy name will be " + entityNameString);
256                                        newRecord.addRecordDetail(entityNameString);
257
258                                }
259                                Eml200DataSource.generateDocumentationForInstance(newRecord);
260                                
261                                // look up EML200DataSource class LSID and create and add
262                                // NamedObjID attribute to instance
263                                if (EML200ActorLSID == null){
264                                        KARCacheManager kcm = KARCacheManager.getInstance();
265                                        Vector<KARCacheContent> list = kcm.getKARCacheContents();
266                                        for(KARCacheContent content : list) {
267                                                if(content.getCacheContent().getClassName().equals(Eml200DataSource.class.getName())) {
268                                                        EML200ActorLSID = content.getLsid();
269                                                }
270                                        }
271                                }
272                                NamedObjId lsidSA = new NamedObjId(newRecord, NamedObjId.NAME);
273                                lsidSA.setExpression(EML200ActorLSID);
274
275                                resultRecordArray[i] = newRecord;
276                        } catch (Exception e) {
277                                continue;
278                        }
279                }// for
280                return resultRecordArray;
281        }
282
283        /*
284         * Method to transform array of AnyRecordType to array of EML2ResultsetItem
285         */
286        private Vector transformResultsetType(ResultsetType result,
287                        String titleReturnFieldString, String entityReturnFieldString) {
288                Vector itemList = new Vector();
289                if (result == null) {
290                        return itemList;
291                }
292                ResultsetTypeRecord[] records = result.getRecord();
293                if (records == null) {
294                        return itemList;
295                }
296
297                ResultsetTypeResultsetMetadata metadata = result.getResultsetMetadata();
298                String titleId = getIdForGivenReturnField(titleReturnFieldString,
299                                namespace, metadata);
300                log.debug("The title id for eml2 is " + titleId);
301                String entityId = getIdForGivenReturnField(entityReturnFieldString,
302                                namespace, metadata);
303                log.debug("The entity id for eml2 is " + entityId);
304                int arraySize = records.length;
305                // transfer every records from source to a dest - EML2ResultsetItem obj
306                for (int i = 0; i < arraySize; i++) {
307                        ResultsetTypeRecord currentRecord = records[i];
308                        if (currentRecord == null) {
309                                continue;
310                        }
311                        String docid = currentRecord.getIdentifier();
312                        log.debug("The doc id after parsing resultset is " + docid);
313                        // if couldn't find identifier, we don't need it
314                        if (docid == null || docid.trim().equals("")) {
315                                continue;
316                        }
317                        String recordTitle = null;
318                        Vector entityNameList = new Vector();
319                        ResultsetTypeRecordReturnField[] recordReturnFieldList = currentRecord
320                                        .getReturnField();
321                        if (recordReturnFieldList == null) {
322                                continue;
323                        }
324                        int length = recordReturnFieldList.length;
325                        for (int j = 0; j < length; j++) {
326                                ResultsetTypeRecordReturnField currentReturnField = recordReturnFieldList[j];
327                                if (currentReturnField == null) {
328                                        continue;
329                                }
330                                String returnFieldId = currentReturnField.getId();
331                                String returnFieldValue = currentReturnField.get_value();
332                                if (returnFieldId != null && !returnFieldId.trim().equals("")) {
333                                        if (titleId != null && returnFieldId.equals(titleId)) {
334                                                log.debug("The title after parsing is  "
335                                                                + returnFieldValue);
336                                                recordTitle = returnFieldValue;
337                                                recordTitle = replaceDotByDash(recordTitle);
338                                        }
339                                        if (entityId != null && returnFieldId.equals(entityId)) {
340                                                log.debug("The original entity is " + returnFieldValue);
341                                                returnFieldValue = replaceDotByDash(returnFieldValue);
342                                                entityNameList.add(returnFieldValue);
343                                        }
344                                }
345
346                        }// for
347                        if (recordTitle == null) {
348                                recordTitle = UNKNOWNTITLE + i;
349                        }
350                        SortableResultRecord newItem = new SortableResultRecord(
351                                        recordTitle, docid, entityNameList);
352                        itemList.add(newItem);
353
354                }// for
355                Collections.sort(itemList, new SortableResultRecordComparator());
356                return itemList;
357        }
358
359        /*
360         * A method to get an id for given returnfield and namespace in a metadata. if
361         * more than one can be found, we only chose the first one
362         */
363        private String getIdForGivenReturnField(String givenReturnField,
364                        String givenNameSpace, ResultsetTypeResultsetMetadata metadata) {
365                String id = null;
366                if (givenReturnField == null || givenNameSpace == null
367                                || metadata == null) {
368                        return id;
369                }
370
371                ResultsetTypeResultsetMetadataRecordStructure structure = metadata
372                                .getRecordStructure();
373                if (structure != null) {
374                        
375                        ResultsetTypeResultsetMetadataNamespace[] rtrmn = metadata.getNamespace();
376                        for (int i=0; i< rtrmn.length; i++){
377                                //String nameSpace = metadata.getNamespace().get_value().toString();
378                                String nameSpace = rtrmn[i].get_value().toString();
379                                if (nameSpace != null && nameSpace.equals(givenNameSpace)) {
380                                        log.debug("The target namespace " + nameSpace + " is found");
381                                        ResultsetTypeResultsetMetadataRecordStructureReturnField[] returnFieldList = structure
382                                                .getReturnField();
383                                        if (returnFieldList != null) {
384                                                int length = returnFieldList.length;
385                                                for (int j = 0; j < length; j++) {
386                                                        ResultsetTypeResultsetMetadataRecordStructureReturnField currentReturnField = returnFieldList[j];
387                                                        if (currentReturnField != null) {
388                                                                String returnFieldName = currentReturnField
389                                                                        .getName();
390                                                                String returnFieldId = currentReturnField.getId();
391                                                                if (returnFieldName != null
392                                                                        && returnFieldName.equals(givenReturnField)) {
393                                                                        id = returnFieldId;
394                                                                        if (id != null) {
395                                                                                log.debug("find the id " + id);
396                                                                                break;
397                                                                        }
398                                                                }
399                                                        }// if currentReturnField != null)
400                                                }// for
401                                        }// if returnFieldList !=null
402                                }// if namespace !=null
403                        }// for i < rtrmn.length
404                } // if structure != null
405                log.debug("the final id  for given namespace" + givenNameSpace
406                                + " and given return field " + givenReturnField + " is " + id);
407                return id;
408        }
409
410        /**
411         * Creates a the ResultRecord items (derived from Source) and adds them into
412         * the container
413         * 
414         * @param aResults
415         * @param aEndPointURLStr
416         * @param aContainer
417         * @param aResultList
418         * @throws SAXException
419         * @throws IOException
420         * @throws EcoGridException
421         * @throws NameDuplicationException
422         * @throws IllegalActionException
423         */
424        public boolean addResultsetRecordsToContainer(ResultsetType results,
425                        String endpoint, CompositeEntity container, Vector aResultList)
426                        throws SAXException, IOException, EcoGridException,
427                        NameDuplicationException, IllegalActionException {
428                // parse the resultset into ResultRecord array and stored it into
429                // a vector
430                try {
431
432                        ResultRecord[] recordArray = transformResultset(results, endpoint,
433                                        container);
434                        if (recordArray != null) {
435                                // put the array into vector which will store the ResultRecord
436                                // from one
437                                // search scope
438                                ResultRecord.transformResultRecordArrayToVector(recordArray,
439                                                aResultList);
440                        }
441
442                        return true;
443                } catch (Exception ee) {
444                        log.debug("The error to transform from resultset to ResultRecord ",
445                                        ee);
446                }
447                return false;
448        }
449
450        /**
451         * 
452         * @return Returns a unique name that describes this class, often it is the
453         *         name of the class that implements the interface
454         */
455        public String getName() {
456                return getClass().getName();
457        }
458
459        /**
460     * 
461     */
462        public String getBriefName() {
463                return "Ecological";
464        }
465
466        /**
467         * 
468         * @return returns the number of results that for this data.
469         */
470        public int getNumResults() {
471                return _numResults;
472        }
473
474}// Eml200EcoGridQueryTransfer