ValueConverter.java

  1. /*
  2.  * #%L
  3.  * wcm.io
  4.  * %%
  5.  * Copyright (C) 2015 wcm.io
  6.  * %%
  7.  * Licensed under the Apache License, Version 2.0 (the "License");
  8.  * you may not use this file except in compliance with the License.
  9.  * You may obtain a copy of the License at
  10.  *
  11.  *      http://www.apache.org/licenses/LICENSE-2.0
  12.  *
  13.  * Unless required by applicable law or agreed to in writing, software
  14.  * distributed under the License is distributed on an "AS IS" BASIS,
  15.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16.  * See the License for the specific language governing permissions and
  17.  * limitations under the License.
  18.  * #L%
  19.  */
  20. package io.wcm.tooling.commons.contentpackagebuilder;

  21. import java.io.InputStream;
  22. import java.lang.reflect.Array;
  23. import java.math.BigDecimal;
  24. import java.net.URI;
  25. import java.util.Calendar;
  26. import java.util.Date;
  27. import java.util.UUID;

  28. import javax.jcr.Binary;
  29. import javax.jcr.Item;
  30. import javax.jcr.ItemVisitor;
  31. import javax.jcr.Node;
  32. import javax.jcr.Property;
  33. import javax.jcr.PropertyType;
  34. import javax.jcr.RepositoryException;
  35. import javax.jcr.Session;
  36. import javax.jcr.Value;
  37. import javax.jcr.ValueFormatException;
  38. import javax.jcr.nodetype.NodeType;
  39. import javax.jcr.nodetype.PropertyDefinition;

  40. import org.apache.commons.lang3.StringUtils;
  41. import org.apache.jackrabbit.util.ISO8601;
  42. import org.apache.jackrabbit.vault.util.DocViewProperty;

  43. /**
  44.  * Converts an value to string for a content property in XML including type prefix.
  45.  */
  46. final class ValueConverter {

  47.   static final String PN_PRIVILEGES = "rep:privileges";

  48.   /**
  49.    * Converts an object to a string representation.
  50.    * Supported are String, Boolean, Integer, Long, Double, BigDecimal, Date, Calendar and arrays of them.
  51.    * @param value value
  52.    * @return Converted value
  53.    */
  54.   public String toString(String propertyName, Object value) {
  55.     if (value == null) {
  56.       return "";
  57.     }

  58.     Value[] values;
  59.     boolean multiple = value.getClass().isArray();
  60.     if (multiple) {
  61.       values = new Value[Array.getLength(value)];
  62.       int lastPropertyType = PropertyType.UNDEFINED;
  63.       for (int i = 0; i < values.length; i++) {
  64.         values[i] = toValue(propertyName, Array.get(value, i));
  65.         if (lastPropertyType == PropertyType.UNDEFINED) {
  66.           lastPropertyType = values[i].getType();
  67.         }
  68.         else if (lastPropertyType != values[i].getType()) {
  69.           throw new IllegalArgumentException("Mixing different value types within array not allowed: " +
  70.               PropertyType.nameFromValue(lastPropertyType) + ", " + PropertyType.nameFromValue(values[i].getType())
  71.               + ", propertyName=" + propertyName + ", value=" + value);
  72.         }
  73.       }
  74.     }
  75.     else {
  76.       values = new Value[] { toValue(propertyName, value) };
  77.     }

  78.     Property prop = new MockProperty(propertyName, multiple, values);
  79.     try {
  80.       return DocViewProperty.format(prop);
  81.     }
  82.     catch (RepositoryException ex) {
  83.       throw new IllegalStateException("Unable to format property value (" + propertyName + "): " + value, ex);
  84.     }
  85.   }

  86.   private Value toValue(String propertyName, Object value) {
  87.     if (value instanceof String) {
  88.       if (StringUtils.equals(propertyName, PN_PRIVILEGES)) {
  89.         return new MockValue(value.toString(), PropertyType.NAME);
  90.       }
  91.       else {
  92.         return new MockValue(value.toString(), PropertyType.STRING);
  93.       }
  94.     }
  95.     if (value instanceof Boolean) {
  96.       return new MockValue(((Boolean)value).toString(), PropertyType.BOOLEAN);
  97.     }
  98.     if (value instanceof Integer || value instanceof Long) {
  99.       return new MockValue(Long.toString(((Number)value).longValue()), PropertyType.LONG);
  100.     }
  101.     if (value instanceof Float || value instanceof Double) {
  102.       return new MockValue(Double.toString(((Number)value).doubleValue()), PropertyType.DECIMAL);
  103.     }
  104.     if (value instanceof BigDecimal) {
  105.       return new MockValue(((BigDecimal)value).toString(), PropertyType.DECIMAL);
  106.     }
  107.     if (value instanceof Date) {
  108.       Calendar calendar = Calendar.getInstance();
  109.       calendar.setTime((Date)value);
  110.       return new MockValue(ISO8601.format(calendar), PropertyType.DATE);
  111.     }
  112.     if (value instanceof Calendar) {
  113.       return new MockValue(ISO8601.format((Calendar)value), PropertyType.DATE);
  114.     }
  115.     if (value instanceof UUID) {
  116.       return new MockValue(((UUID)value).toString(), PropertyType.REFERENCE);
  117.     }
  118.     if (value instanceof URI) {
  119.       return new MockValue(((URI)value).toString(), PropertyType.URI);
  120.     }
  121.     throw new IllegalArgumentException("Type not supported: " + value.getClass().getName());
  122.   }


  123.   /**
  124.    * Mock implementations of JCR property and value to be handed over to {@link DocViewProperty#format(Property)}
  125.    * method.
  126.    */
  127.   private static class MockProperty implements Property, PropertyDefinition {

  128.     private final String name;
  129.     private final boolean multiple;
  130.     private final Value[] values;

  131.     MockProperty(String name, boolean multiple, Value[] values) {
  132.       this.name = name;
  133.       this.multiple = multiple;
  134.       this.values = values;
  135.     }

  136.     @Override
  137.     public String getName() {
  138.       return name;
  139.     }

  140.     @Override
  141.     public int getType() {
  142.       if (values.length > 0) {
  143.         return values[0].getType();
  144.       }
  145.       return PropertyType.UNDEFINED;
  146.     }

  147.     @Override
  148.     public boolean isMultiple() {
  149.       return multiple;
  150.     }

  151.     @Override
  152.     public Value getValue() throws ValueFormatException {
  153.       if (multiple) {
  154.         throw new ValueFormatException("Property is multiple.");
  155.       }
  156.       return values[0];
  157.     }

  158.     @Override
  159.     public Value[] getValues() throws ValueFormatException {
  160.       if (!multiple) {
  161.         throw new ValueFormatException("Property is not multiple.");
  162.       }
  163.       return values;
  164.     }

  165.     @Override
  166.     public PropertyDefinition getDefinition() {
  167.       return this;
  168.     }


  169.     // -- unsupported methods --

  170.     @Override
  171.     public String getPath() {
  172.       throw new UnsupportedOperationException();
  173.     }

  174.     @Override
  175.     public Item getAncestor(int depth) {
  176.       throw new UnsupportedOperationException();
  177.     }

  178.     @Override
  179.     public Node getParent() {
  180.       throw new UnsupportedOperationException();
  181.     }

  182.     @Override
  183.     public int getDepth() {
  184.       throw new UnsupportedOperationException();
  185.     }

  186.     @Override
  187.     public Session getSession() {
  188.       throw new UnsupportedOperationException();
  189.     }

  190.     @Override
  191.     public boolean isNode() {
  192.       throw new UnsupportedOperationException();
  193.     }

  194.     @Override
  195.     public boolean isNew() {
  196.       throw new UnsupportedOperationException();
  197.     }

  198.     @Override
  199.     public boolean isModified() {
  200.       throw new UnsupportedOperationException();
  201.     }

  202.     @Override
  203.     public boolean isSame(Item otherItem) {
  204.       throw new UnsupportedOperationException();
  205.     }

  206.     @Override
  207.     public void accept(ItemVisitor visitor) {
  208.       throw new UnsupportedOperationException();
  209.     }

  210.     @Override
  211.     public void save() {
  212.       throw new UnsupportedOperationException();
  213.     }

  214.     @Override
  215.     public void refresh(boolean keepChanges) {
  216.       throw new UnsupportedOperationException();
  217.     }

  218.     @Override
  219.     public void remove() {
  220.       throw new UnsupportedOperationException();
  221.     }

  222.     @Override
  223.     public void setValue(Value value) {
  224.       throw new UnsupportedOperationException();
  225.     }

  226.     @Override
  227.     public void setValue(Value[] value) {
  228.       throw new UnsupportedOperationException();
  229.     }

  230.     @Override
  231.     public void setValue(String value) {
  232.       throw new UnsupportedOperationException();
  233.     }

  234.     @Override
  235.     public void setValue(String[] value) {
  236.       throw new UnsupportedOperationException();
  237.     }

  238.     @Override
  239.     public void setValue(InputStream value) {
  240.       throw new UnsupportedOperationException();
  241.     }

  242.     @Override
  243.     public void setValue(Binary value) {
  244.       throw new UnsupportedOperationException();
  245.     }

  246.     @Override
  247.     public void setValue(long value) {
  248.       throw new UnsupportedOperationException();
  249.     }

  250.     @Override
  251.     public void setValue(double value) {
  252.       throw new UnsupportedOperationException();
  253.     }

  254.     @Override
  255.     public void setValue(BigDecimal value) {
  256.       throw new UnsupportedOperationException();
  257.     }

  258.     @Override
  259.     public void setValue(Calendar value) {
  260.       throw new UnsupportedOperationException();
  261.     }

  262.     @Override
  263.     public void setValue(boolean value) {
  264.       throw new UnsupportedOperationException();
  265.     }

  266.     @Override
  267.     public void setValue(Node value) {
  268.       throw new UnsupportedOperationException();
  269.     }

  270.     @Override
  271.     public String getString() {
  272.       throw new UnsupportedOperationException();
  273.     }

  274.     @Override
  275.     public InputStream getStream() {
  276.       throw new UnsupportedOperationException();
  277.     }

  278.     @Override
  279.     public Binary getBinary() {
  280.       throw new UnsupportedOperationException();
  281.     }

  282.     @Override
  283.     public long getLong() {
  284.       throw new UnsupportedOperationException();
  285.     }

  286.     @Override
  287.     public double getDouble() {
  288.       throw new UnsupportedOperationException();
  289.     }

  290.     @Override
  291.     public BigDecimal getDecimal() {
  292.       throw new UnsupportedOperationException();
  293.     }

  294.     @Override
  295.     public Calendar getDate() {
  296.       throw new UnsupportedOperationException();
  297.     }

  298.     @Override
  299.     public boolean getBoolean() {
  300.       throw new UnsupportedOperationException();
  301.     }

  302.     @Override
  303.     public Node getNode() {
  304.       throw new UnsupportedOperationException();
  305.     }

  306.     @Override
  307.     public Property getProperty() {
  308.       throw new UnsupportedOperationException();
  309.     }

  310.     @Override
  311.     public long getLength() {
  312.       throw new UnsupportedOperationException();
  313.     }

  314.     @Override
  315.     public long[] getLengths() {
  316.       throw new UnsupportedOperationException();
  317.     }

  318.     @Override
  319.     public NodeType getDeclaringNodeType() {
  320.       throw new UnsupportedOperationException();
  321.     }

  322.     @Override
  323.     public boolean isAutoCreated() {
  324.       throw new UnsupportedOperationException();
  325.     }

  326.     @Override
  327.     public boolean isMandatory() {
  328.       throw new UnsupportedOperationException();
  329.     }

  330.     @Override
  331.     public int getOnParentVersion() {
  332.       throw new UnsupportedOperationException();
  333.     }

  334.     @Override
  335.     public boolean isProtected() {
  336.       throw new UnsupportedOperationException();
  337.     }

  338.     @Override
  339.     public int getRequiredType() {
  340.       throw new UnsupportedOperationException();
  341.     }

  342.     @Override
  343.     public String[] getValueConstraints() {
  344.       throw new UnsupportedOperationException();
  345.     }

  346.     @Override
  347.     public Value[] getDefaultValues() {
  348.       throw new UnsupportedOperationException();
  349.     }

  350.     @Override
  351.     public String[] getAvailableQueryOperators() {
  352.       throw new UnsupportedOperationException();
  353.     }

  354.     @Override
  355.     public boolean isFullTextSearchable() {
  356.       throw new UnsupportedOperationException();
  357.     }

  358.     @Override
  359.     public boolean isQueryOrderable() {
  360.       throw new UnsupportedOperationException();
  361.     }

  362.   }

  363.   private static class MockValue implements Value {

  364.     private final String value;
  365.     private final int type;

  366.     MockValue(String value, int type) {
  367.       this.value = value;
  368.       this.type = type;
  369.     }

  370.     @Override
  371.     public String getString() {
  372.       return value;
  373.     }

  374.     @Override
  375.     public int getType() {
  376.       return type;
  377.     }


  378.     // -- unsupported methods --

  379.     @Override
  380.     public InputStream getStream() {
  381.       throw new UnsupportedOperationException();
  382.     }

  383.     @Override
  384.     public Binary getBinary() {
  385.       throw new UnsupportedOperationException();
  386.     }

  387.     @Override
  388.     public long getLong() {
  389.       throw new UnsupportedOperationException();
  390.     }

  391.     @Override
  392.     public double getDouble() {
  393.       throw new UnsupportedOperationException();
  394.     }

  395.     @Override
  396.     public BigDecimal getDecimal() {
  397.       throw new UnsupportedOperationException();
  398.     }

  399.     @Override
  400.     public Calendar getDate() {
  401.       throw new UnsupportedOperationException();
  402.     }

  403.     @Override
  404.     public boolean getBoolean() {
  405.       throw new UnsupportedOperationException();
  406.     }

  407.   }

  408. }