Package er.restadaptor

Source Code of er.restadaptor.ERRESTAdaptorChannel

package er.restadaptor;

import java.io.BufferedInputStream;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import com.webobjects.eoaccess.EOAdaptorChannel;
import com.webobjects.eoaccess.EOAttribute;
import com.webobjects.eoaccess.EOEntity;
import com.webobjects.eoaccess.EOGeneralAdaptorException;
import com.webobjects.eoaccess.EOModel;
import com.webobjects.eoaccess.EOSQLExpression;
import com.webobjects.eoaccess.EOStoredProcedure;
import com.webobjects.eocontrol.EOAndQualifier;
import com.webobjects.eocontrol.EOFetchSpecification;
import com.webobjects.eocontrol.EOKeyValueQualifier;
import com.webobjects.eocontrol.EOOrQualifier;
import com.webobjects.eocontrol.EOQualifier;
import com.webobjects.foundation.NSArray;
import com.webobjects.foundation.NSDictionary;
import com.webobjects.foundation.NSMutableArray;
import com.webobjects.foundation.NSMutableDictionary;
import com.webobjects.foundation.NSMutableSet;
import com.webobjects.foundation.NSSet;
import com.webobjects.foundation.NSTimestampFormatter;

import er.extensions.foundation.ERXMutableURL;
import er.extensions.localization.ERXLocalizer;

public class ERRESTAdaptorChannel extends EOAdaptorChannel {
  private static final NSTimestampFormatter restDateFormat = new NSTimestampFormatter("%Y-%m-%dT%H:%M:%SZ");

  private NSArray<EOAttribute> _attributes;
  private NSMutableArray<NSMutableDictionary<String, Object>> _fetchedRows;
  private int _fetchIndex;
  private boolean _open;

  public ERRESTAdaptorChannel(ERRESTAdaptorContext context) {
    super(context);
    _fetchIndex = -1;
  }

  public ERRESTAdaptorContext context() {
    return (ERRESTAdaptorContext) _context;
  }

  @Override
  public NSArray<EOAttribute> attributesToFetch() {
    return _attributes;
  }

  @Override
  public void cancelFetch() {
    _fetchedRows = null;
    _fetchIndex = -1;
  }

  @Override
  public void closeChannel() {
    _open = false;
  }

  @Override
  public NSArray describeResults() {
    return _attributes;
  }

  @Override
  public NSArray describeTableNames() {
    return NSArray.EmptyArray;
  }

  @Override
  public EOModel describeModelWithTableNames(NSArray anArray) {
    return null;
  }

  @Override
  public void evaluateExpression(EOSQLExpression anExpression) {
    throw new UnsupportedOperationException("ERRESTAdaptorChannel.evaluateExpression");
  }

  @Override
  public void executeStoredProcedure(EOStoredProcedure aStoredProcedure, NSDictionary someValues) {
    throw new UnsupportedOperationException("ERRESTAdaptorChannel.executeStoredProcedure");
  }

  @Override
  public NSMutableDictionary fetchRow() {
    NSMutableDictionary row = null;
    if (_fetchedRows != null && _fetchIndex < _fetchedRows.count()) {
      row = _fetchedRows.objectAtIndex(_fetchIndex++);
    }
    return row;
  }

  @Override
  public boolean isFetchInProgress() {
    return _fetchedRows != null && _fetchIndex < _fetchedRows.count();
  }

  @Override
  public boolean isOpen() {
    return _open;
  }

  @Override
  public void openChannel() {
    if (!_open) {
      _open = true;
    }
  }

  @Override
  public NSDictionary returnValuesForLastStoredProcedureInvocation() {
    throw new UnsupportedOperationException("ERRESTAdaptorChannel.returnValuesForLastStoredProcedureInvocation");
  }

  public NSArray<String> urlPrefixes(EOEntity entity) {
    String urlPrefix = null;
    String externalName = entity.externalName();
    if (externalName != null) {
      String[] externalNames = externalName.split(",");
      if (externalNames.length > 0 && externalNames[0].contains("/")) {
        urlPrefix = externalNames[0];
      }
    }

    if (urlPrefix == null) {
      urlPrefix = "/" + pluralName(entity);
    }

    return new NSArray<String>(urlPrefix.split("\\|"));
  }

  public String pluralName(EOEntity entity) {
    String pluralName = null;

    String externalName = entity.externalName();
    if (externalName != null) {
      String[] externalNames = externalName.split(",");
      if (externalNames.length > 0) {
        if (externalNames[0].contains("/")) {
          if (externalNames.length > 2) {
            pluralName = externalNames[2];
          }
        }
        else if (externalNames.length > 1) {
          pluralName = externalNames[1];
        }
      }
    }

    if (pluralName == null) {
      pluralName = ERXLocalizer.defaultLocalizer().plurifiedString(singularName(entity), 2);
    }

    return pluralName;
  }

  public String singularName(EOEntity entity) {
    String singularName = null;

    String externalName = entity.externalName();
    if (externalName != null) {
      String[] externalNames = externalName.split(",");
      if (externalNames.length > 0) {
        if (externalNames[0].contains("/")) {
          if (externalNames.length > 1) {
            singularName = externalNames[1];
          }
        }
        else {
          singularName = externalNames[0];
        }
      }
    }

    if (singularName == null) {
      singularName = entity.name();
    }

    return singularName;
  }

  public String textValue(Element element) {
    NodeList children = element.getChildNodes();
    String textValue = null;
    for (int i = 0; i < children.getLength(); i++) {
      String value = children.item(i).getNodeValue();
      if (value != null) {
        value = value.trim();
        textValue = value;
        break;
      }
    }
    return textValue;
  }

  public Object convertValue(String strValue, EOAttribute attribute) {
    return strValue;
  }

  @SuppressWarnings( { "cast", "unchecked" })
  public String urlForQualifier(EOEntity entity, EOQualifier qualifier, NSMutableDictionary<String, Object> attributesFromQualifier) {
    StringBuffer urlBuffer = new StringBuffer();

    NSDictionary connectionDictionary = adaptorContext().adaptor().connectionDictionary();
    String url = (String) connectionDictionary.objectForKey("URL");
    if (url == null || url.length() == 0) {
      throw new IllegalArgumentException("There is no URL specified for the connection dictionary " + connectionDictionary + ".");
    }

    if (url.endsWith("/")) {
      urlBuffer.append(url.substring(0, url.length() - 1));
    }
    else {
      urlBuffer.append(url);
    }

    NSArray<String> urlPrefixes = urlPrefixes(entity);

    if (urlPrefixes.count() == 1) {
      urlBuffer.append(urlPrefixes.objectAtIndex(0));
    }
    else {
      String bestUrlPrefix = null;
      int bestMatchCount = 0;

      NSSet<String> qualifierKeys = (NSSet<String>) qualifier.allQualifierKeys();
      for (String urlPrefix : urlPrefixes) {
        NSSet<String> urlVariableNames = variableNamesForUrl(urlPrefix);
        if (urlVariableNames.count() >= bestMatchCount && urlVariableNames.isSubsetOfSet(qualifierKeys)) {
          bestUrlPrefix = urlPrefix;
          bestMatchCount = urlVariableNames.count();
        }
      }

      if (bestUrlPrefix == null) {
        throw new IllegalArgumentException("The qualifier " + qualifier + " was insufficient to fetch " + entity.name() + " objects with one of the URLs " + urlPrefixes + ".");
      }

      urlBuffer.append(bestUrlPrefix);
    }

    if (qualifier != null) {
      processQualifier(entity, qualifier, urlBuffer, attributesFromQualifier);
    }

    urlBuffer.append(".xml");

    System.out.println("ERRESTAdaptorChannel.urlForQualifier: " + urlBuffer);

    return urlBuffer.toString();
  }

  protected NSSet<String> variableNamesForUrl(String url) {
    NSMutableSet<String> variableNames = new NSMutableSet<String>();
    Matcher matcher = Pattern.compile("\\[([^]]+)\\]").matcher(url);
    while (matcher.find()) {
      variableNames.addObject(matcher.group(1));
    }
    return variableNames;
  }

  @SuppressWarnings( { "cast", "unchecked" })
  protected void processQualifier(EOEntity entity, EOQualifier qualifier, StringBuffer urlBuffer, NSMutableDictionary<String, Object> attributesFromQualifier) {
    if (qualifier instanceof EOKeyValueQualifier) {
      EOKeyValueQualifier eokvq = (EOKeyValueQualifier) qualifier;
      String key = eokvq.key();
      Object value = eokvq.value();
      EOAttribute keyAttribute = entity.attributeNamed(key);
      if (entity.primaryKeyAttributes().containsObject(keyAttribute)) {
        urlBuffer.append("/");
        urlBuffer.append(value);
      }
      else {
        String var = "[" + key + "]";
        int varIndex = urlBuffer.indexOf(var);
        if (varIndex != -1) {
          urlBuffer.replace(varIndex, varIndex + var.length(), value.toString());
        }
      }

      if (value != null) {
        attributesFromQualifier.setObjectForKey(value, key);
      }
    }
    else if (qualifier instanceof EOAndQualifier) {
      NSArray<EOQualifier> childQualifiers = (NSArray<EOQualifier>) ((EOAndQualifier) qualifier).qualifiers();
      for (EOQualifier childQualifier : childQualifiers) {
        processQualifier(entity, childQualifier, urlBuffer, attributesFromQualifier);
      }
    }
    else if (qualifier instanceof EOOrQualifier) {
      NSArray<EOQualifier> childQualifiers = (NSArray<EOQualifier>) ((EOOrQualifier) qualifier).qualifiers();
      if (childQualifiers.count() == 1) {
        processQualifier(entity, childQualifiers.objectAtIndex(0), urlBuffer, attributesFromQualifier);
      }
    }
  }

  @Override
  public void selectAttributes(NSArray attributesToFetch, EOFetchSpecification fetchSpecification, boolean shouldLock, EOEntity entity) {
    if (entity == null) {
      throw new IllegalArgumentException("null entity.");
    }
    if (attributesToFetch == null) {
      throw new IllegalArgumentException("null attributes.");
    }
    setAttributesToFetch(attributesToFetch);

    try {
      _fetchIndex = 0;

      NSMutableDictionary<String, Object> attributesFromQualifier = new NSMutableDictionary<String, Object>();
      ERXMutableURL url = new ERXMutableURL(urlForQualifier(entity, fetchSpecification.qualifier(), attributesFromQualifier));
      InputStream urlStream = new BufferedInputStream(url.toURL().openStream());
      Document document;
      try {
        document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(urlStream);
      }
      finally {
        urlStream.close();
      }
      document.normalize();

      _fetchedRows = new NSMutableArray<NSMutableDictionary<String, Object>>();
      NodeList rowElements = document.getElementsByTagName(singularName(entity));
      for (int rowNum = 0; rowNum < rowElements.getLength(); rowNum++) {
        NSMutableDictionary<String, Object> row = new NSMutableDictionary<String, Object>();
        Element rowElement = (Element) rowElements.item(rowNum);
        for (int attributeNum = 0; attributeNum < attributesToFetch.count(); attributeNum++) {
          EOAttribute attribute = (EOAttribute) attributesToFetch.objectAtIndex(attributeNum);
          String columnName = attribute.columnName();
          NodeList attributeElements = rowElement.getElementsByTagName(columnName);

          Object value;
          if (attributeElements.getLength() == 0) {
            if (rowElement.hasAttribute(columnName)) {
              Attr columnAttribute = rowElement.getAttributeNode(columnName);
              value = convertValue(columnAttribute.getValue(), attribute);
            }
            else {
              value = null;
            }
          }
          else if (attributeElements.getLength() > 1) {
            throw new EOGeneralAdaptorException("There was more than one column named '" + columnName + "'.");
          }
          else {
            Element attributeElement = (Element) attributeElements.item(0);
            if ("true".equals(attributeElement.getAttribute("nil"))) {
              value = null;
            }
            else {
              String strValue = textValue(attributeElement);
              if (attributeElement.hasAttribute("type")) {
                String type = attributeElement.getAttribute("type");
                if ("bigit".equals(type)) {
                  value = new BigDecimal(strValue);
                }
                else if ("boolean".equals(type)) {
                  value = Boolean.parseBoolean(strValue);
                }
                else if ("datetime".equals(type)) {
                  value = ERRESTAdaptorChannel.restDateFormat.parseObject(strValue);
                }
                else if ("double".equals(type)) {
                  value = Double.parseDouble(strValue);
                }
                else if ("float".equals(type)) {
                  value = Float.parseFloat(strValue);
                }
                else if ("integer".equals(type)) {
                  value = Integer.parseInt(strValue);
                }
                else if ("short".equals(type)) {
                  value = Short.parseShort(strValue);
                }
                else {
                  throw new IllegalArgumentException("Unknown type '" + type + "'.");
                }
              }
              else {
                value = convertValue(strValue, attribute);
              }
            }
          }

          if (value != null) {
            row.setObjectForKey(value, attribute.name());
          }
        }

        // Just in case you qualified against attributes that ended up not
        // being returned in the results, we augment the resulting row
        // with the key-value pairs from your qualifier.
        if (attributesFromQualifier.count() > 0) {
          for (String qualifierAttributeName : attributesFromQualifier.allKeys()) {
            if (!row.containsKey(qualifierAttributeName)) {
              EOAttribute qualifierAttribute = entity.attributeNamed(qualifierAttributeName);
              if (qualifierAttribute != null && attributesToFetch.containsObject(qualifierAttribute)) {
                row.setObjectForKey(attributesFromQualifier.objectForKey(qualifierAttributeName), qualifierAttributeName);
              }
            }
          }
        }

        // Because we can only interpret parts of your qualifier, we now run the
        // fetched dictionaries through the in-memory qualifier and let it weed
        // out results using the more complicatd qualifiers.
        EOQualifier qualifier = fetchSpecification.qualifier();
        if (qualifier == null || qualifier.evaluateWithObject(row)) {
          _fetchedRows.addObject(row);
        }
        else {
          System.out.println("ERRESTAdaptorChannel.selectAttributes: skipping " + row + " (" + qualifier + ")");
        }
      }
    }
    catch (EOGeneralAdaptorException e) {
      throw e;
    }
    catch (Throwable e) {
      e.printStackTrace();
      throw new EOGeneralAdaptorException("Failed to fetch '" + entity.name() + "' with fetch specification '" + fetchSpecification + "': " + e.getMessage());
    }
  }

  @SuppressWarnings("unchecked")
  @Override
  public void setAttributesToFetch(NSArray attributesToFetch) {
    if (attributesToFetch == null) {
      throw new IllegalArgumentException("ERMemoryAdaptorChannel.setAttributesToFetch: null attributes.");
    }
    _attributes = attributesToFetch;
  }

  @Override
  public int updateValuesInRowsDescribedByQualifier(NSDictionary updatedRow, EOQualifier qualifier, EOEntity entity) {
    try {
      throw new EOGeneralAdaptorException("ERRESTAdaptorChannel.updateValuesInRowsDescribedByQualifier not supported.");
    }
    catch (EOGeneralAdaptorException e) {
      throw e;
    }
    catch (Throwable e) {
      e.printStackTrace();
      throw new EOGeneralAdaptorException("Failed to update '" + entity.name() + "' row " + updatedRow + " with qualifier " + qualifier + ": " + e.getMessage());
    }
  }

  @Override
  public void insertRow(NSDictionary row, EOEntity entity) {
    try {
      throw new EOGeneralAdaptorException("ERRESTAdaptorChannel.insertRow not supported.");
    }
    catch (EOGeneralAdaptorException e) {
      throw e;
    }
    catch (Throwable e) {
      e.printStackTrace();
      throw new EOGeneralAdaptorException("Failed to insert '" + entity.name() + "' with row " + row + ": " + e.getMessage());
    }
  }

  @Override
  public int deleteRowsDescribedByQualifier(EOQualifier qualifier, EOEntity entity) {
    try {
      throw new EOGeneralAdaptorException("ERRESTAdaptorChannel.deleteRowsDescribedByQualifier not supported.");
    }
    catch (EOGeneralAdaptorException e) {
      throw e;
    }
    catch (Throwable e) {
      e.printStackTrace();
      throw new EOGeneralAdaptorException("Failed to delete '" + entity.name() + "' with qualifier " + qualifier + ": " + e.getMessage());
    }
  }
}
TOP

Related Classes of er.restadaptor.ERRESTAdaptorChannel

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.