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