protected Map<String, Preference> toPreferencesMap(String xml) {
    if (Validator.isNull(xml)) {
      return Collections.emptyMap();
    }

    Map<String, Preference> preferencesMap = _preferencesMapPortalCache.get(xml);

    if (preferencesMap != null) {
      return preferencesMap;
    }

    XMLEventReader xmlEventReader = null;

    try {
      XMLInputFactory xmlInputFactory = StAXReaderUtil.getXMLInputFactory();

      xmlEventReader = xmlInputFactory.createXMLEventReader(new UnsyncStringReader(xml));

      while (xmlEventReader.hasNext()) {
        XMLEvent xmlEvent = xmlEventReader.nextEvent();

        if (xmlEvent.isStartElement()) {
          StartElement startElement = xmlEvent.asStartElement();

          String elementName = startElement.getName().getLocalPart();

          if (elementName.equals("preference")) {
            Preference preference = readPreference(xmlEventReader);

            if (preferencesMap == null) {
              preferencesMap = new HashMap<String, Preference>();
            }

            preferencesMap.put(preference.getName(), preference);
          }
        }
      }
    } catch (XMLStreamException xse) {
      throw new SystemException(xse);
    } finally {
      if (xmlEventReader != null) {
        try {
          xmlEventReader.close();
        } catch (XMLStreamException xse) {
        }
      }
    }

    if (preferencesMap == null) {
      preferencesMap = Collections.emptyMap();
    }

    _preferencesMapPortalCache.put(xml, preferencesMap);

    return preferencesMap;
  }
  protected Preference readPreference(XMLEventReader xmlEventReader) throws XMLStreamException {

    String name = null;
    List<String> values = new ArrayList<String>();
    boolean readOnly = false;

    while (xmlEventReader.hasNext()) {
      XMLEvent xmlEvent = xmlEventReader.nextEvent();

      if (xmlEvent.isStartElement()) {
        StartElement startElement = xmlEvent.asStartElement();

        String elementName = startElement.getName().getLocalPart();

        if (elementName.equals("name")) {
          name = StAXReaderUtil.read(xmlEventReader);
        } else if (elementName.equals("value")) {
          String value = StAXReaderUtil.read(xmlEventReader);

          values.add(value);
        } else if (elementName.equals("read-only")) {
          String value = StAXReaderUtil.read(xmlEventReader);

          readOnly = GetterUtil.getBoolean(value);
        }
      } else if (xmlEvent.isEndElement()) {
        EndElement endElement = xmlEvent.asEndElement();

        String elementName = endElement.getName().getLocalPart();

        if (elementName.equals("preference")) {
          break;
        }
      }
    }

    return new Preference(name, values.toArray(new String[values.size()]), readOnly);
  }
  public static Tuple parseMethod(String xml) throws IOException {
    XMLStreamReader xmlStreamReader = null;

    try {
      XMLInputFactory xmlInputFactory = StAXReaderUtil.getXMLInputFactory();

      xmlStreamReader = xmlInputFactory.createXMLStreamReader(new UnsyncStringReader(xml));

      xmlStreamReader.nextTag();
      xmlStreamReader.nextTag();
      xmlStreamReader.next();

      String methodName = xmlStreamReader.getText();
      List<Object> arguments = new ArrayList<Object>();

      xmlStreamReader.nextTag();

      String name = xmlStreamReader.getLocalName();

      while (!name.equals("methodCall")) {
        xmlStreamReader.nextTag();

        name = xmlStreamReader.getLocalName();

        if (name.equals("param")) {
          xmlStreamReader.nextTag();

          name = xmlStreamReader.getLocalName();

          int event = xmlStreamReader.next();

          if (event == XMLStreamConstants.START_ELEMENT) {
            name = xmlStreamReader.getLocalName();

            xmlStreamReader.next();

            String text = xmlStreamReader.getText();

            if (name.equals("string")) {
              arguments.add(text);
            } else if (name.equals("int") || name.equals("i4")) {
              arguments.add(GetterUtil.getInteger(text));
            } else if (name.equals("double")) {
              arguments.add(GetterUtil.getDouble(text));
            } else if (name.equals("boolean")) {
              arguments.add(GetterUtil.getBoolean(text));
            } else {
              throw new IOException("XML-RPC not implemented for " + name);
            }

            xmlStreamReader.nextTag();
            xmlStreamReader.nextTag();
            xmlStreamReader.nextTag();
          } else {
            String text = xmlStreamReader.getText();

            arguments.add(text);

            xmlStreamReader.nextTag();
            xmlStreamReader.nextTag();
          }

          name = xmlStreamReader.getLocalName();
        }
      }

      return new Tuple(methodName, arguments.toArray());
    } catch (Exception e) {
      throw new IOException(e.getMessage());
    } finally {
      if (xmlStreamReader != null) {
        try {
          xmlStreamReader.close();
        } catch (Exception e) {
        }
      }
    }
  }
  public static Response parseResponse(String xml) throws XmlRpcException {
    XMLStreamReader xmlStreamReader = null;

    try {
      XMLInputFactory xmlInputFactory = StAXReaderUtil.getXMLInputFactory();

      xmlStreamReader = xmlInputFactory.createXMLStreamReader(new UnsyncStringReader(xml));

      xmlStreamReader.nextTag();
      xmlStreamReader.nextTag();

      String name = xmlStreamReader.getLocalName();

      if (name.equals("params")) {
        String description = null;

        xmlStreamReader.nextTag();
        xmlStreamReader.nextTag();

        int event = xmlStreamReader.next();

        if (event == XMLStreamConstants.START_ELEMENT) {
          xmlStreamReader.next();

          description = xmlStreamReader.getText();
        } else {
          description = xmlStreamReader.getText();
        }

        return XmlRpcUtil.createSuccess(description);
      } else if (name.equals("fault")) {
        int code = 0;
        String description = null;

        xmlStreamReader.nextTag();
        xmlStreamReader.nextTag();

        for (int i = 0; i < 2; i++) {
          xmlStreamReader.nextTag();
          xmlStreamReader.nextTag();

          xmlStreamReader.next();

          String valueName = xmlStreamReader.getText();

          if (valueName.equals("faultCode")) {
            xmlStreamReader.nextTag();
            xmlStreamReader.nextTag();
            xmlStreamReader.nextTag();

            name = xmlStreamReader.getLocalName();

            if (name.equals("int") || name.equals("i4")) {
              xmlStreamReader.next();

              code = GetterUtil.getInteger(xmlStreamReader.getText());
            }

            xmlStreamReader.nextTag();
            xmlStreamReader.nextTag();
            xmlStreamReader.nextTag();
          } else if (valueName.equals("faultString")) {
            xmlStreamReader.nextTag();
            xmlStreamReader.nextTag();

            int event = xmlStreamReader.next();

            if (event == XMLStreamConstants.START_ELEMENT) {
              xmlStreamReader.next();

              description = xmlStreamReader.getText();

              xmlStreamReader.nextTag();
            } else {
              description = xmlStreamReader.getText();
            }

            xmlStreamReader.nextTag();
            xmlStreamReader.nextTag();
          }
        }

        return XmlRpcUtil.createFault(code, description);
      }

      return null;
    } catch (Exception e) {
      throw new XmlRpcException(xml, e);
    } finally {
      if (xmlStreamReader != null) {
        try {
          xmlStreamReader.close();
        } catch (Exception e) {
        }
      }
    }
  }