Package org.apache.oodt.profile.handlers.lightweight

Source Code of org.apache.oodt.profile.handlers.lightweight.LightweightProfileServer

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/


package org.apache.oodt.profile.handlers.lightweight;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.Stack;
import org.apache.oodt.commons.Configuration;
import org.apache.oodt.commons.ExecServerConfig;
import org.apache.oodt.profile.Profile;
import org.apache.oodt.profile.ProfileException;
import org.apache.oodt.profile.handlers.ProfileHandler;
import org.apache.oodt.commons.util.DOMParser;
import org.apache.oodt.commons.util.XML;
import org.apache.oodt.xmlquery.QueryElement;
import org.apache.oodt.xmlquery.XMLQuery;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

/**
* A lightweight profile server.
*
* A lightweight profile server is lightweight because it doesn't rely on any external
* database or other search/retrieval mechanism.
*
* @author Kelly
*/
final public class LightweightProfileServer implements ProfileHandler {
  /**
   * Create a lightweight profile server using defaults.
   *
   * @throws IOException If an I/O error occurs.
   * @throws SAXException If an error occurs parsing the profile file.
   * @throws MalformedURLException If the default profile URL is malformed.
   */
  public LightweightProfileServer() throws IOException, SAXException, MalformedURLException {
    this(System.getProperties());
  }

  /**
   * Create a lightweight profile server using the given properties.
   *
   * The property we use is
   * <code>profiles.url</code>,
   * which is the URL of the file containing profile definitions that this server
   * will read and serve.
   *
   * @param props Properties.
   * @throws IOException If an I/O error occurs.
   * @throws SAXException If an error occurs parsing the profile file.
   * @throws MalformedURLException If the URL to the profile file is malformed.
   */
  public LightweightProfileServer(Properties props) throws IOException, SAXException, MalformedURLException {
    this(new URL(props.getProperty("org.apache.oodt.profile.handlers.LightweightProfileServer.profiles.url",
                        props.getProperty("org.apache.oodt.profile.webServer.baseURL", "http://eda.jpl.nasa.gov")
                        + "/profiles.xml")),
      props.getProperty("org.apache.oodt.profile.handlers.LightweightProfileServer.id", "lightweight"));
  }

  /**
   * Create a lightweight profile server using the given URL.
   *
   * @param url URL of the file containing profile definitions that this server will read and serve.
   * @param id Identifier to report for when this handler is queried by name.
   * @throws IOException If an I/O error occurs.
   * @throws SAXException If an error occurs parsing the profile file.
   * @throws MalformedURLException If <var>url</var> is malformed.
   */
  public LightweightProfileServer(URL url, String id) throws IOException, SAXException, MalformedURLException {
    this.id = id;

    // Get the list of profiles from the cache, if it's there.
    profiles = (List) cache.get(url);
    if (profiles != null) return;

    // It wasn't in the cache, so create a parser to parse the file.  We only
    // deal with correct files, so turn on validation and install an error
    // handler that will throw an exception.
    profiles = new ArrayList();
    DOMParser parser = XML.createDOMParser();
    parser.setErrorHandler(new ErrorHandler() {
      public void error(SAXParseException ex) throws SAXParseException {
        System.err.println("Parse error line " + ex.getLineNumber() + " column "
          + ex.getColumnNumber() + ": " + ex.getMessage());
        throw ex;
      }
      public void warning(SAXParseException ex) {
        System.err.println("Parse warning: " + ex.getMessage());
      }
      public void fatalError(SAXParseException ex) throws SAXParseException {
        throw ex;
      }
    });

    // Parse the file.
    InputSource inputSource = new InputSource(url.toString());
    parser.parse(inputSource);
    Document doc = parser.getDocument();

    // Normalize it and get the document element, and from that, create a list
    // of profiles, and add it to the cache.
    doc.normalize();
    Element root = doc.getDocumentElement();
    profiles = Profile.createProfiles(root, new SearchableObjectFactory());
    cache.put(url, profiles);

    System.err.println("LightweightProfileServer ready");
  }

  public List findProfiles(XMLQuery query) throws ProfileException {
    // Compute the where-expression based on the query string, and start off
    // with an empty set of results.
    Set matchingProfiles = new HashSet();
    WhereExpression whereExpression = createWhereExpression(query);

    // Search each profile, and add the results of the search to the set of results.
    for (Iterator i = profiles.iterator(); i.hasNext();) {
      SearchableProfile profile = (SearchableProfile) i.next();

      // Search the profile with the where-expression.
      Result result = profile.search(whereExpression);

      // If there are any matching elements, add the profile to the set.
      if (!result.matchingElements().isEmpty())
        matchingProfiles.add(profile);
    }

    // Convert from set to list.
    return new ArrayList(matchingProfiles);
  }

  /**
   * Get a single profile matching the given ID.
   *
   * @param profID a {@link String} value.
   * @return a {@link Profile} value.
   */
  public Profile get(String profID) {
    if (profID == null) return null;
    Profile rc = null;
    for (Iterator i = profiles.iterator(); i.hasNext();) {
      Profile p = (Profile) i.next();
      if (p.getProfileAttributes().getID().equals(profID)) {
        rc = p;
        break;
      }
    }
    return rc;
  }

  /**
   * Convert the XML query to a where expression.
   *
   * @param query The query to convert
   * @return The equivalent, simplified where expression.
   */
  private static WhereExpression createWhereExpression(XMLQuery query) {
    Stack stack = new Stack();
    
    // Collect together the where- and from-sets, joined with an "and".
    List allElements = new ArrayList(query.getWhereElementSet());
    List fromElements = query.getFromElementSet();
    if (!fromElements.isEmpty()) {
      allElements.addAll(fromElements);
      allElements.add(new QueryElement("LOGOP", "AND"));
    }
   
    // For each item in the where-set
    for (Iterator i = allElements.iterator(); i.hasNext();) {
      QueryElement queryElement = (QueryElement) i.next();

      // Get the keyword and its type.
      String keyword = queryElement.getValue();
      String type = queryElement.getRole();

      if (type.equals("elemName")) {
        // It's an element name, so push the element name.
        stack.push(keyword);
      } else if (type.equals("LITERAL")) {
        // It's a literal value, so push the value.
        stack.push(keyword);
      } else if (type.equals("LOGOP")) {
        // It's a logical operator.  Pop the operands off the
        // stack and push the appropriate operator back on.
        if (keyword.equals("AND")) {
          stack.push(new AndExpression((WhereExpression) stack.pop(), (WhereExpression)stack.pop()));
        } else if (keyword.equals("OR")) {
          stack.push(new OrExpression((WhereExpression) stack.pop(), (WhereExpression)stack.pop()));
        } else if (keyword.equals("NOT")) {
          stack.push(new NotExpression((WhereExpression) stack.pop()));
        } else throw new IllegalArgumentException("Illegal operator \"" + keyword + "\" in query");
      } else if (type.equals("RELOP")) {
        // It's a relational operator.  Pop the element name and
        // literal value off the stack, and push the operator
        // expression on with the given operator.
        stack.push(new OperatorExpression((String) stack.pop(), (String) stack.pop(), keyword));
      }
    }

    // If there's nothing on the stack, we're given nothing, so give back everything.
    if (stack.size() == 0)
      return new ConstantExpression(true);
    else if (stack.size() > 1)
      throw new IllegalStateException("Imbalanced expression in query");
   
    // Simplify/optimize the where-expression and return it.
    return ((WhereExpression) stack.pop()).simplify();
  }

  /** {@inheritDoc} */
  public String getID() {
    return id;
  }

  /** Profiles I serve. */
  private List profiles;

  /**
   * Cache of profiles.
   *
   * This is a mapping from {@link java.net.URL} of the profile source to the {@link
   * List} of profiles.  We do this so we don't have to keep rereading and reparsing
   * the possibly huge profile file each time an object of this class is
   * instantiated.
   *
   * <p><em>Question:</em> Since when are multiple LightweightProfileServers being
   * constructed anyway?  There's just one per profile server process, and it's
   * using just the one file, so there should be no need for this cache.  Who added
   * this?  And if it were me, what was I smoking?
   */
  private static Map cache = new HashMap();

  /** My ID. */
  private String id;

  /**
   * Application execution entry point.
   *
   * This lets you try out a query to the Lightweight Profile server.
   *
   * @param argv Command-line arguments.
   * @throws Exception Should any error occur.
   */
  public static void main(String[] argv) throws Exception {
    if (argv.length == 0) {
      System.err.println("Usage: <query>...");
      System.exit(1);
    }

    // Create the profile
    LightweightProfileServer lp = new LightweightProfileServer();

    // Gather together the command-line arguments into a single long string.
    StringBuffer b = new StringBuffer();
    for (int i = 0; i < argv.length; ++i)
      b.append(argv[i]).append(' ');

    // Create the query object from the expression.
    XMLQuery query = new XMLQuery(b.toString().trim(), /*id*/"cli1", /*title*/"CmdLine-1",
      /*desc*/"This is a query entered on the command-line", /*ddId*/null, /*resultModeId*/null,
      /*propType*/null, /*propLevels*/null, XMLQuery.DEFAULT_MAX_RESULTS);

    // Display the results.
    System.out.println(lp.findProfiles(query));

    // All done.
    System.exit(0);
  }
}
TOP

Related Classes of org.apache.oodt.profile.handlers.lightweight.LightweightProfileServer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.