Package org.cipango.kaleo.xcap

Source Code of org.cipango.kaleo.xcap.XcapService

// ========================================================================
// Copyright 2008-2009 NEXCOM Systems
// ------------------------------------------------------------------------
// Licensed 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.cipango.kaleo.xcap;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Level;
import org.cipango.kaleo.Constants;
import org.cipango.kaleo.xcap.XcapResourceImpl.NodeType;
import org.cipango.kaleo.xcap.dao.XcapDao;
import org.cipango.kaleo.xcap.dao.XmlResource;
import org.cipango.kaleo.xcap.util.HexString;
import org.cipango.kaleo.xcap.util.RequestUtil;
import org.cipango.kaleo.xcap.util.XcapUtil;
import org.iso_relax.verifier.VerifierConfigurationException;
import org.jaxen.JaxenException;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;

public class XcapService extends AbstractLifeCycle
{
  public static final String POST = "POST";
  public static final String PUT = "PUT";
  public static final String DELETE = "DELETE";
  public static final String GET = "GET";
 
  private static final String XPOINTER_PREFIX = "xmlns(";
  private static final String XPOINTER_PREFIX_REGEX = "xmlns\\(";

  private final Logger _log = LoggerFactory.getLogger(XcapService.class);

  private Map<String, XcapResourceProcessor> _processors;
  private XcapDao _dao;

  private boolean _validate;
  private boolean _validateOnGet;
  private String _rootName;
  private Map<String, List<XcapListener>> _listeners = new HashMap<String, List<XcapListener>>();
 
  @Override
  protected void doStart() throws Exception
  {
    setRootName("xcap");
    _validate = _validateOnGet = false;
    _processors = new HashMap<String, XcapResourceProcessor>();
    createIetfProcessors();
    createOmaProcessors();
    _dao.init(_processors.values());
    initXcapCaps();
  }
 
  public void createIetfProcessors()
  {
    XcapProcessorImpl processor = new XcapProcessorImpl();
    processor.setAuid("resource-lists");
    processor.setDefaultNamespacePrefix("rl");
    processor.setMimeType("application/resource-lists+xml");
    Map<String, String> namespaceContext = new HashMap<String, String>();
    namespaceContext.put("rl", "urn:ietf:params:xml:ns:resource-lists");
    processor.setNamespaceContext(namespaceContext);
    addProcessor(processor);
   
    processor = new XcapProcessorImpl();
    processor.setAuid("pres-rules");
    processor.setDefaultNamespacePrefix("cr");
    processor.setMimeType("application/auth-policy+xml");
    namespaceContext = new HashMap<String, String>();
    namespaceContext.put("pr", "urn:ietf:params:xml:ns:pres-rules");
    namespaceContext.put("cr", "urn:ietf:params:xml:ns:common-policy");
    processor.setNamespaceContext(namespaceContext);
    processor.setXsdSchemaPath("/schema/common-policy.xsd");
    processor.setName("Presence-rules processor");
    addProcessor(processor);
     
    addProcessor(new XcapCapsProcessor());
  }
 
  public void createOmaProcessors()
  {
    XcapProcessorImpl processor = new XcapProcessorImpl();
    processor.setAuid("org.openmobilealliance.access-rules");
    processor.setDefaultNamespacePrefix("cr");
    processor.setMimeType("application/auth-policy+xml");
    Map<String, String> namespaceContext = new HashMap<String, String>();
    namespaceContext.put("pr", "urn:ietf:params:xml:ns:pres-rules");
    namespaceContext.put("cr", "urn:ietf:params:xml:ns:common-policy");
    namespaceContext.put("cp", "urn:oma:xml:xdm:common-policy");
    processor.setNamespaceContext(namespaceContext);
    processor.setName("OMA shared policy processor");
    processor.setXsdSchemaPath("/schema/common-policy.xsd");
    addProcessor(processor);
   
    processor = new XcapProcessorImpl();
    processor.setAuid("org.openmobilealliance.pres-rules");
    processor.setDefaultNamespacePrefix("cr");
    processor.setMimeType("application/auth-policy+xml");
    namespaceContext = new HashMap<String, String>();
    namespaceContext.put("pr", "urn:ietf:params:xml:ns:pres-rules");
    namespaceContext.put("cr", "urn:ietf:params:xml:ns:common-policy");
    namespaceContext.put("cp", "urn:oma:xml:xdm:common-policy");
    processor.setNamespaceContext(namespaceContext);
    processor.setName("OMA presence rules processor");
    processor.setXsdSchemaPath("/schema/common-policy.xsd");
    addProcessor(processor);
   
    processor = new XcapProcessorImpl();
    processor.setAuid("org.openmobilealliance.group-usage-list");
    processor.setDefaultNamespacePrefix("rl");
    processor.setMimeType("application/vnd.oma.group-usage-list+xml");
    namespaceContext = new HashMap<String, String>();
    namespaceContext.put("rl", "urn:ietf:params:xml:ns:resource-lists");
    namespaceContext.put("oru", "urn:oma:xml:xdm:resource-list:oma-uriusage");
    namespaceContext.put("oxe", "urn:oma:xml:xdm:extensions");
    processor.setNamespaceContext(namespaceContext);
    processor.setName("OMA group usage list processor");
    processor.setXsdSchemaPath("/schema/OMA-SUP-XSD_xdm_extensions-V1_0-20080916-C.xsd");
    addProcessor(processor);
   
    processor = new XcapProcessorImpl();
    processor.setAuid("org.openmobilealliance.user-profile");
    processor.setDefaultNamespacePrefix("ur");
    processor.setMimeType("application/vnd.oma.user-profile+xml");
    namespaceContext = new HashMap<String, String>();
    namespaceContext.put("ur", "urn:oma:xml:xdm:user-profile");
    processor.setNamespaceContext(namespaceContext);
    processor.setName("OMA shared profile XDM processor");
    processor.setXsdSchemaPath("/schema/OMA-SUP-XSD_xdm_userProfile-V1_0-20070724-C.xsd");
    addProcessor(processor);
   
    processor = new XcapProcessorImpl();
    processor.setAuid("org.openmobilealliance.locked-user-profile");
    processor.setDefaultNamespacePrefix("ur");
    processor.setMimeType("application/vnd.oma.user-profile+xml");
    namespaceContext = new HashMap<String, String>();
    namespaceContext.put("ur", "urn:oma:xml:xdm:user-profile");
    processor.setNamespaceContext(namespaceContext);
    processor.setName("OMA locked user profile processor");
    processor.setXsdSchemaPath("/schema/OMA-SUP-XSD_xdm_userProfile-V1_0-20070724-C.xsd");
    addProcessor(processor);
   
    processor = new XcapProcessorImpl();
    processor.setAuid("org.openmobilealliance.groups");
    processor.setDefaultNamespacePrefix("ls");
    processor.setMimeType("application/vnd.oma.poc.groups+xml");
    namespaceContext = new HashMap<String, String>();
    namespaceContext.put("ls", "urn:oma:xml:poc:list-service");
    processor.setNamespaceContext(namespaceContext);
    processor.setName("OMA shared group XDM processor");
    // TODO set schema
    addProcessor(processor);
  }
 
  private void initXcapCaps() throws XcapException, IOException
  {
    StringBuilder sb = new StringBuilder();
    sb.append("<?xml version=\"1.0\"?>\n");
    sb.append("<xcap-caps xmlns=\"urn:ietf:params:xml:ns:xcap-caps\"\n");
    sb.append("  xmlns:xsi=\"htt//www.w3.org/2001/XMLSchema-instance\"\n");
    sb.append("  xsi:schemaLocation=\"urn:ietf:params:xml:ns:xcap-caps xcap-caps.xsd\">\n");
    sb.append("<auids>\n");
    for (XcapResourceProcessor processor : _processors.values())
      sb.append("\t<auid>").append(processor.getAuid()).append("</auid>\n");
    sb.append("</auids>\n");
    sb.append("<namespaces>\n");
    for (XcapResourceProcessor processor : _processors.values())
    {
      for (String namespace : processor.getNamespaceContext().values())
        sb.append("\t<namespace>").append(namespace).append("</namespace>\n");
    }
    sb.append("</namespaces>\n");
    sb.append("</xcap-caps>");
    XcapResourceImpl resource = getResource(
        new XcapUri("xcap-caps/global/index", ""),
        true, "", null);
    _dao.update(resource, sb.toString());
    _dao.save(resource);
  }
 
  public void addProcessor(XcapResourceProcessor processor)
  {
    _processors.put(processor.getAuid(), processor);
  }
 
  public boolean isAuidRegistered(String auid)
  {
    return _processors.containsKey(auid);
  }

  public XcapResourceImpl getResource(XcapUri xcapUri, boolean isPut,
      String requestUrlHead, Map<String, String> requestNamespaceContext)
      throws XcapException
  {
    XcapResourceProcessor processor = _processors.get(xcapUri.getAuid());

    if (processor == null)
      throw new XcapException("Not supported auid: " + xcapUri.getAuid()
          + " in URI: " + xcapUri,
          HttpServletResponse.SC_NOT_FOUND);

    Document document = null;
    XcapResourceImpl resource = new XcapResourceImpl();

    resource.setXcapUri(xcapUri);
    resource.setProcessor(processor);

    XmlResource xmlResource = _dao.getDocument(xcapUri, isPut && !xcapUri.hasNodeSeparator());
   
    if (xmlResource == null)
    {
      if (isPut)
      {
        locatingParent(xcapUri, requestUrlHead);
        resource.setCreation(true);
        return resource;
      }
      else
      {
        XcapException e = new XcapException("Resource: "
            + xcapUri.getDocumentSelector() + " not found",
            HttpServletResponse.SC_NOT_FOUND);
        e.setLevel(Level.INFO);
        throw e;
      }
    }
    resource.setDocument(xmlResource);
    // TODO check rootDirectory is in parent dir.

    // TODO authenticate & authorization

    if (_validateOnGet)
    {
      try
      {
        XcapUtil.validate(document, processor.getXsdSchema());
      }
      catch (XcapException e)
      {
        _log.warn("Unable to validated document:" + e.getMessage(), e);
      }
    }

    if (resource.isAllDocument())
      return resource;
   

    String nodeSelector = XcapUtil.insertDefaultNamespace(xcapUri
        .getNodeSelector(), processor.getDefaultNamespacePrefix());

    if (_log.isDebugEnabled())
      _log.debug("select node " + nodeSelector + " in "
          + xcapUri.getDocumentSelector());

    if (requestNamespaceContext == null)
      requestNamespaceContext = new HashMap<String, String>();
    requestNamespaceContext.putAll(processor.getNamespaceContext());

    resource.setNamespaceContext(requestNamespaceContext);
   
    XmlResource xmlResource2 = _dao.getNode(resource, nodeSelector);

    if (xmlResource2 == null)
    {
      if (isPut)
      {
        // XCAP 8.2.1. Locating the Parent
        String parent = locatingParent(resource, nodeSelector,
            xcapUri.getDocumentSelector(), requestUrlHead);
        resource.setCreation(true);
        NodeType nodeType;
        String nodeName = nodeSelector.substring(parent.length());
        // /@id is an attribute and /service[@id="1"] is an
        // element
        if (nodeName.indexOf('@') != -1
            && nodeName.indexOf('[') == -1)
        {
          nodeType = NodeType.ATTRIBUTE;
          nodeName = nodeName.substring(nodeName.indexOf('@') + 1);
        }
        else
          nodeType = NodeType.ELEMENT;
        resource.setParent(parent, nodeType, nodeName);
      }
      else
      {
        XcapException e = new XcapException("Resource: "
            + xcapUri + " not found (no node selected)",
            HttpServletResponse.SC_NOT_FOUND);
        e.setLevel(Level.INFO);
        throw e;
      }
    }
    else
    {
      resource.setCreation(false);
      resource.setSelectedResource(xmlResource2);
    }

    return resource;
  }

  private void locatingParent(XcapUri uri, String requestUrlHead)
      throws XcapException
  {
    // See XCAP 8.2.1. Locating the Parent

    String ancestor = _dao.getFirstExistAncestor(uri);

    if (uri.hasNodeSeparator() || uri.getDocumentSelector().substring(ancestor.length() + 1).indexOf('/') != -1)
    {
      XcapException e = new XcapException("parent does not exist",
          HttpServletResponse.SC_CONFLICT);
      StringBuffer sb = new StringBuffer();
      sb.append(XcapException.XCAP_ERROR_HEADER);
      sb.append("<no-parent><ancestor>");
      String url = requestUrlHead + _rootName + ancestor;
      sb.append(RequestUtil.filter(url));
      sb.append("</ancestor></no-parent>");
      sb.append(XcapException.XCAP_ERROR_FOOTER);

      e.setContent(XcapException.XCAP_ERROR_CONTENT_TYPE, sb.toString()
          .getBytes());
      throw e;
    }
  }

  /**
   * Throws a XcapException if parent of nodeSelector does not exist else
   * returns the parent of nodeSelector.
   *
   * @param resource
   * @param nodeSelector
   * @param documentSelector
   * @throws XcapException
   * @throws XMLDBException
   * @throws XMLDBException
   * @throws JaxenException
   */
  private String locatingParent(XcapResource resource, String nodeSelector,
      String documentSelector, String requestUrlHead)
      throws XcapException
  {
    // See XCAP 8.2.1. Locating the Parent
    int index = nodeSelector.lastIndexOf('/');
    String parent = nodeSelector.substring(0, index);
    String firstExistAncestor = getFirstExistNodeAncestor(resource, parent);
    if (!parent.equals(firstExistAncestor))
    {
      XcapException e = new XcapException("parent does not exist",
          HttpServletResponse.SC_CONFLICT);
      StringBuffer sb = new StringBuffer();
      sb.append(XcapException.XCAP_ERROR_HEADER);
      sb.append("<no-parent><ancestor>");
      String url = requestUrlHead + _rootName + documentSelector;
      if (firstExistAncestor != null)
      {
        url += XcapUri.NODE_SELECTOR_SEPARATOR
            + firstExistAncestor;
      }
      sb.append(RequestUtil.filter(url));
      sb.append("</ancestor></no-parent>");
      sb.append(XcapException.XCAP_ERROR_FOOTER);

      e.setContent(XcapException.XCAP_ERROR_CONTENT_TYPE, sb.toString()
          .getBytes());
      throw e;
    }
    else
    {
      return parent;
    }
  }

  private String getFirstExistNodeAncestor(XcapResource resource, String nodeSelector) throws XcapException
  {
    XmlResource xmlResource = _dao.getNode(resource, nodeSelector);
    if (xmlResource != null)
      return nodeSelector;
    else
    {
      int index = nodeSelector.lastIndexOf('/');
      if (index != -1)
      {
        String parent = nodeSelector.substring(0, index);
        return getFirstExistNodeAncestor(resource, parent);
      }
      else
        return null;
    }
  }

  public void service(HttpServletRequest request,
      HttpServletResponse response) throws IOException, SAXException, VerifierConfigurationException
  {
    String method = request.getMethod();
    String requestUri = request.getRequestURI();
    StringBuffer requestUrl = request.getRequestURL();
    String head = requestUrl.substring(0, requestUrl.indexOf(requestUri));

    try
    {
      if ("POST".equals(method))
      {
        throw new XcapException(
            HttpServletResponse.SC_METHOD_NOT_ALLOWED);
      }

      Map<String, String> context = getXpointer(request);
     
      XcapUri xcapUri = new XcapUri(requestUri, _rootName);
      XcapResourceImpl resource = getResource(xcapUri, PUT
          .equals(method), head, context);
     
      ifMatchConditionalProcessing(request, resource);
      ifNoneMatchConditionalProcessing(request, resource);

      resource.setAction(method);

      if (method.equals(GET))
        doGet(response, resource);
      else if (method.equals(PUT))
        doPut(request, resource);
      else if (method.equals(DELETE))
        doDelete(request, resource);


      if (method.equals(PUT) || method.equals(DELETE))
      {
        checkIfSameNodeSelected(resource);
        resource.getProcessor().processResource(resource);
        _dao.save(resource);
        notifyResourceChanged(resource);
      }

      String newEtag = getEtag(resource);
      resource.setNewEtag(newEtag);
      response.setHeader(Constants.ETAG, newEtag);
      response.setStatus(HttpServletResponse.SC_OK);
      if (_log.isDebugEnabled())
        _log.debug(method + " " + requestUri + " sucessful");
    }
    catch (XcapException e)
    {
      if (e.shouldShowStackTrace())
        _log.info("Unable to process " + method + " " + requestUri, e);
      else
        _log.info("Unable to process " + method + " " + requestUri
            + ": " + e.getMessage());
      e.sendResponse(response);
    }
  }

  private void doGet(HttpServletResponse response, XcapResourceImpl resource) throws IOException
  {
    response.setContentType(resource.getMimeType());
    if (resource.isAllDocument())
    {
      response.getOutputStream().write(
          resource.getDocument().getBytes());
    }
    else
    {
      XmlResource selectedResource = resource.getSelectedResource();
      switch (resource.getNodeType())
      {
      case ATTRIBUTE:
        response.getOutputStream().write(((Attr) selectedResource.getDom()).getValue().getBytes());
        break;
      case ELEMENT:
        response.getOutputStream().write(selectedResource.getBytes());
        break;
      case NAMESPACE:     
        Node node = selectedResource.getDom();
        String prefix = "<" + node.getNodeName() + " ";
        response.getOutputStream().write(prefix.getBytes());
        response.getOutputStream().write(node.getNamespaceURI().getBytes());
        response.getOutputStream().write("/>".getBytes());
        break;
      default:
        break;
      }

    }
  }

  private void doPut(HttpServletRequest request, XcapResourceImpl resource)
      throws IOException, XcapException, SAXException, VerifierConfigurationException
  {
    throwExceptionIfNamespace(resource);
    String content = getContent(request, resource);

    _dao.update(resource, content);

    if (_validate)
      XcapUtil.validate(resource.getDocument().getDom(), resource
          .getProcessor().getXsdSchema());
   
    validateSpecificAppResource(resource)
  }

  private void doDelete(HttpServletRequest request, XcapResourceImpl resource)
      throws XcapException, SAXException, VerifierConfigurationException
  {
    throwExceptionIfNamespace(resource);
    _dao.delete(resource);
    if (!resource.isAllDocument())
    {
      if (_validate)
      {
        XcapUtil.validate(resource.getDocument().getDom(),
            resource.getProcessor().getXsdSchema());
      }
      validateSpecificAppResource(resource);
    }
  }

  private void validateSpecificAppResource(XcapResourceImpl resource)
      throws XcapException
  {
    if (!resource.getProcessor().validateResource(resource))
    {
      XcapException e = new XcapException(
          "Specific application resource validation failed",
          HttpServletResponse.SC_CONFLICT);
      StringBuffer sb = new StringBuffer();
      sb.append(XcapException.XCAP_ERROR_HEADER);
      sb.append("<constraint-failure/>");
      sb.append(XcapException.XCAP_ERROR_FOOTER);
      e.setContent(XcapException.XCAP_ERROR_CONTENT_TYPE, sb.toString()
          .getBytes());
      throw e;
    }
  }

  @SuppressWarnings("unchecked")
  private void ifMatchConditionalProcessing(HttpServletRequest request,
      XcapResourceImpl resource) throws XcapException
  {
    Enumeration ifMatchEnum = request.getHeaders(Constants.IF_MATCH);
    String currentEtag = getEtag(resource);
    resource.setPreviousEtag(currentEtag);

    if (ifMatchEnum != null && ifMatchEnum.hasMoreElements())
    {

      while (ifMatchEnum.hasMoreElements())
      {
        String element = (String) ifMatchEnum.nextElement();
        String[] matchEtags = element.split(",");

        for (int i = 0; i < matchEtags.length; i++)
        {
          if (Constants.WILCARD.equals(matchEtags[i].trim()))
          {
            if (resource.isAllDocument() && resource.isCreation())
            {
              throw new XcapException(
                  "Conditional processing failed: "
                      + "If-match: * and new document creation",
                  HttpServletResponse.SC_PRECONDITION_FAILED);
            }
            else if (_log.isDebugEnabled())
              _log.debug("wilcard entity tags has matched");
          }
          else if (currentEtag.equals(matchEtags[i].trim()))
          {
            if (_log.isDebugEnabled())
              _log.debug("entity tag has matched");
            return;
          }
        }
      }
      throw new XcapException("Conditional processing failed: "
          + "If-match: present and none match",
          HttpServletResponse.SC_PRECONDITION_FAILED);
    }
  }

  @SuppressWarnings("unchecked")
  private void ifNoneMatchConditionalProcessing(HttpServletRequest request,
      XcapResourceImpl resource) throws XcapException
  {
    Enumeration ifNoneMatchEnum = request
        .getHeaders(Constants.IF_NONE_MATCH);

    if (ifNoneMatchEnum != null && ifNoneMatchEnum.hasMoreElements())
    {
      String currentEtag = getEtag(resource);
      while (ifNoneMatchEnum.hasMoreElements())
      {
        String element = (String) ifNoneMatchEnum.nextElement();
        String[] noneMatchEtags = element.split(",");

        for (int i = 0; i < noneMatchEtags.length; i++)
        {
          if (Constants.WILCARD.equals(noneMatchEtags[i].trim()))
          {
            if (resource.isAllDocument() && resource.isCreation())
            {
              if (_log.isDebugEnabled())
                _log.debug("wilcard entity tag has matched");
            }
            else
            {
              throw new XcapException(
                  "Conditional processing failed: "
                      + "If-None-match: * and not new document creation",
                  HttpServletResponse.SC_PRECONDITION_FAILED);
            }
          }
          else if (currentEtag.equals(noneMatchEtags[i].trim()))
          {
            if ("GET".equals(request.getMethod()))
            {
              throw new XcapException(
                  "Conditional processing failed: "
                      + "If-None-match: present and match",
                  HttpServletResponse.SC_NOT_MODIFIED);
            }
            else
            {
              throw new XcapException(
                  "Conditional processing failed: "
                      + "If-None-match: present and match",
                  HttpServletResponse.SC_PRECONDITION_FAILED);
            }
          }
        }
      }
    }
  }

  private void throwExceptionIfNamespace(XcapResourceImpl resource)
      throws XcapException
  {
    if (!resource.isAllDocument()
        && resource.getNodeType() == NodeType.NAMESPACE)
    {
      // If the request URI contained a namespace-selector, the server
      // MUST
      // reject the request with a 405 (Method Not Allowed) and MUST
      // include
      // an Allow header field including the GET method.
      XcapException e = new XcapException(
          HttpServletResponse.SC_METHOD_NOT_ALLOWED);
      e.addHeader(Constants.ALLOW, GET);
      throw e;
    }
  }

  public String getEtag(XcapResourceImpl resource) {
    try {
            if (resource.getDocument() == null)
              return "notExist";
           
            MessageDigest md = MessageDigest.getInstance("MD5");
                      
            md.update(resource.getDocument().getBytes());
            return HexString.bufferToHex(md.digest());
        } catch (NoSuchAlgorithmException e) {
           _log.error("Unable to initialize Message Digest (for etags).", e);
           return "defaultEtag";
        } catch (Throwable e) {
            _log.error("Unable to to create etags", e);
            return "defaultEtag";
         }
  }

  /**
   * XCAP 8.2.2. Verifying Document Content
   */
  private String getContent(HttpServletRequest request,
      XcapResourceImpl resource) throws XcapException
  {
    if (request.getContentLength() <= 0)
    {
      throw new XcapException("No content received ",
          HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE);
    }

    // If the MIME type in the Content-Type header field of the request is
    // not equal to the MIME type defined for the application usage, the
    // server MUST reject the request with a 415.
    if (!resource.getMimeType().equals(request.getContentType()))
    {
      throw new XcapException("Bad content type: "
          + request.getContentType() + " should be:"
          + resource.getMimeType(),
          HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE);
    }

    try
    {
      InputStream is = request.getInputStream();
      ByteArrayOutputStream os = new ByteArrayOutputStream();
      int read;
      byte[] buffer = new byte[128];
      while ((read = is.read(buffer)) != -1)
      {
        os.write(buffer, 0, read);
      }
      return new String(new String(os.toByteArray()));
    }
    catch (Throwable e)
    {
      XcapException e1 = new XcapException("Unable to read content",
          HttpServletResponse.SC_CONFLICT);
      StringBuffer sb = new StringBuffer();
      sb.append(XcapException.XCAP_ERROR_HEADER);
      sb.append("<not-xml-att-value/>");
      sb.append(XcapException.XCAP_ERROR_FOOTER);

      e1.setContent(XcapException.XCAP_ERROR_CONTENT_TYPE, sb
          .toString().getBytes());
      throw e1;
    }

  }

  @SuppressWarnings("unchecked")
  private Map<String, String> getXpointer(HttpServletRequest request)
  {
    Enumeration enumeration = request.getParameterNames();
    Map<String, String> context = new HashMap<String, String>();
    while (enumeration.hasMoreElements())
    {
      String name = (String) enumeration.nextElement();
      if (name.startsWith(XPOINTER_PREFIX))
      {
        String prefix = name.substring(XPOINTER_PREFIX.length());
        String[] values = request.getParameter(name).split(
            XPOINTER_PREFIX_REGEX);
        String ns = values[0].substring(0, values[0].indexOf(')'));
        context.put(prefix, ns);

        for (int i = 1; i < values.length; i++)
        {
          int index = values[i].indexOf('=');
          prefix = values[i].substring(0, index);
          ns = values[i].substring(index + 1, values[i].indexOf(')'));
          context.put(prefix, ns);
        }
      }
    }
    return context;
  }

  private void checkIfSameNodeSelected(XcapResourceImpl resource)
      throws XcapException
  {
    if (!resource.getXcapUri().hasNodeSeparator() || resource.isCreation())
      return;

    try
    {
      // boolean match =
      // resource.getSelectedNode().matches(resource.getNodeSelector());
     
      XmlResource xmlResource = _dao.getNode(resource);
      boolean valid = false;
      if (xmlResource == null)
      {
        valid = resource.getAction().equals(DELETE);
      }
      else
      {
        Node node = xmlResource.getDom();
        valid = node.equals(resource.getSelectedResource().getDom())
            && resource.getAction().equals(PUT);
      }
      if (!valid)
      {
        XcapException e1 = new XcapException(
            "Request no more select the same node",
            HttpServletResponse.SC_CONFLICT);
        StringBuffer sb = new StringBuffer();
        sb.append(XcapException.XCAP_ERROR_HEADER);
        sb.append("<cannot-insert/>");
        sb.append(XcapException.XCAP_ERROR_FOOTER);
        e1.setContent(XcapException.XCAP_ERROR_CONTENT_TYPE, sb
            .toString().getBytes());
        throw e1;
      }
    }
    catch (XcapException e)
    {
      throw e;
    }
    catch (Throwable e)
    {
      XcapException e1 = new XcapException(
          "Cannot check if select the same node",
          HttpServletResponse.SC_CONFLICT, e);
      StringBuffer sb = new StringBuffer();
      sb.append(XcapException.XCAP_ERROR_HEADER);
      sb.append("<cannot-insert/>");
      sb.append(XcapException.XCAP_ERROR_FOOTER);
      e1.setContent(XcapException.XCAP_ERROR_CONTENT_TYPE, sb.toString()
          .getBytes());
      throw e1;
    }
  }

  public XcapDao getDao()
  {
    return _dao;
  }

  public void setDao(XcapDao dao)
  {
    _dao = dao;
  }

  public boolean isValidate()
  {
    return _validate;
  }

  public void setValidate(boolean validate)
  {
    _validate = validate;
  }

  public boolean isValidateOnGet()
  {
    return _validateOnGet;
  }

  public void setValidateOnGet(boolean validateOnGet)
  {
    _validateOnGet = validateOnGet;
  }

  public String getRootName()
  {
    return _rootName;
  }

  public void setRootName(String name)
  {
    if (name == "" || "/".equals(name))
      _rootName = "/";
    else
    {
      if (name.startsWith("/") && name.endsWith("/"))
        _rootName = name;
      else
        _rootName = "/" +  name + "/"
    }
  }
 
  public void addListener(XcapListener l, XcapUri uri)
  {
    synchronized (_listeners)
    {
      List<XcapListener> list = _listeners.get(uri.getDocumentSelector());
      if (list == null)
      {
        list = new ArrayList<XcapListener>();
        _listeners.put(uri.getDocumentSelector(), list);
      }
      if (!list.contains(l))
        list.add(l);
    }
  }
 
  public void removeListener(XcapListener l, XcapUri uri)
  {
    synchronized (_listeners)
    {
      List<XcapListener> list = _listeners.get(uri.getDocumentSelector());
      if (list != null)
      {
        list.remove(l);
        if (list.isEmpty())
          _listeners.remove(uri.getDocumentSelector());
      }
    }
  }
 
  private void notifyResourceChanged(XcapResource resource)
  {
    List<XcapListener> list = null;
    synchronized (_listeners)
    {
      list = _listeners.get(resource.getXcapUri().getDocumentSelector());
    }
    if (list != null)
    {
      Iterator<XcapListener> it = list.iterator();
      while (it.hasNext())
        it.next().documentChanged(resource);
    }
  }

}
TOP

Related Classes of org.cipango.kaleo.xcap.XcapService

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.