Beispiel #1
0
 protected Field resolveSubField(ListType listType, String subName, boolean fallbackOnSubElement) {
   Type itemType = listType.getFieldType();
   if (itemType.isComplexType() && subName != null) {
     ComplexType complexType = (ComplexType) itemType;
     Field subField = complexType.getField(subName);
     return subField;
   }
   if (fallbackOnSubElement) {
     return listType.getField();
   }
   return null;
 }
Beispiel #2
0
 /** Reads state into a complex property. */
 protected void readComplexProperty(T state, ComplexProperty complexProperty)
     throws PropertyException {
   if (state == null) {
     complexProperty.init(null);
     return;
   }
   if (complexProperty instanceof BlobProperty) {
     Blob blob = getValueBlob(state);
     complexProperty.init((Serializable) blob);
     return;
   }
   for (Property property : complexProperty) {
     String name = property.getField().getName().getPrefixedName();
     name = internalName(name);
     Type type = property.getType();
     if (type.isSimpleType()) {
       // simple property
       Object value = state.getSingle(name);
       if (value instanceof Delta) {
         value = ((Delta) value).getFullValue();
       }
       property.init((Serializable) value);
     } else if (type.isComplexType()) {
       // complex property
       T childState = getChild(state, name, type);
       readComplexProperty(childState, (ComplexProperty) property);
       ((ComplexProperty) property).removePhantomFlag();
     } else {
       ListType listType = (ListType) type;
       if (listType.getFieldType().isSimpleType()) {
         // array
         Object[] array = state.getArray(name);
         array = typedArray(listType.getFieldType(), array);
         property.init(array);
       } else {
         // complex list
         Field listField = listType.getField();
         List<T> childStates = getChildAsList(state, name);
         // TODO property.init(null) if null children in DBS
         List<Object> list = new ArrayList<>(childStates.size());
         for (T childState : childStates) {
           ComplexProperty p =
               (ComplexProperty) complexProperty.getRoot().createProperty(property, listField, 0);
           readComplexProperty(childState, p);
           list.add(p.getValue());
         }
         property.init((Serializable) list);
       }
     }
   }
 }
Beispiel #3
0
 protected void readPrefetchField(
     T state,
     Field field,
     String xpathGeneric,
     String xpath,
     Set<String> prefixes,
     Map<String, Serializable> prefetch) {
   String name = field.getName().getPrefixedName();
   Type type = field.getType();
   xpathGeneric = xpathGeneric == null ? name : xpathGeneric + '/' + name;
   xpath = xpath == null ? name : xpath + '/' + name;
   if (!prefixes.contains(xpathGeneric)) {
     return;
   }
   if (type.isSimpleType()) {
     // scalar
     Object value = state.getSingle(name);
     prefetch.put(xpath, (Serializable) value);
   } else if (type.isComplexType()) {
     // complex property
     T childState = getChild(state, name, type);
     if (childState != null) {
       readPrefetch(childState, (ComplexType) type, xpathGeneric, xpath, prefixes, prefetch);
     }
   } else {
     // array or list
     ListType listType = (ListType) type;
     if (listType.getFieldType().isSimpleType()) {
       // array
       Object[] value = state.getArray(name);
       prefetch.put(xpath, value);
     } else {
       // complex list
       List<T> childStates = getChildAsList(state, name);
       Field listField = listType.getField();
       xpathGeneric += "/*";
       int i = 0;
       for (T childState : childStates) {
         readPrefetch(
             childState,
             (ComplexType) listField.getType(),
             xpathGeneric,
             xpath + '/' + i++,
             prefixes,
             prefetch);
       }
     }
   }
 }
Beispiel #4
0
 /**
  * Builds the list.
  *
  * @param document the document
  * @param element the element
  * @param ltype the ltype
  * @param list the list
  * @throws IOException Signals that an I/O exception has occurred.
  */
 private static void buildList(Document document, Element element, ListType ltype, List list)
     throws IOException {
   Field field = ltype.getField();
   for (Object obj : list) {
     buildProperty(document, element, field, obj);
   }
 }
Beispiel #5
0
 protected void setValueField(T state, Field field, Object value) throws PropertyException {
   Type type = field.getType();
   String name = field.getName().getPrefixedName(); // normalize from map key
   name = internalName(name);
   // TODO we could check for read-only here
   if (type.isSimpleType()) {
     // scalar
     state.setSingle(name, value);
   } else if (type.isComplexType()) {
     // complex property
     T childState = getChildForWrite(state, name, type);
     setValueComplex(childState, field, value);
   } else {
     // array or list
     ListType listType = (ListType) type;
     Type fieldType = listType.getFieldType();
     if (fieldType.isSimpleType()) {
       // array
       if (value instanceof List) {
         value = ((List<?>) value).toArray(new Object[0]);
       }
       state.setArray(name, (Object[]) value);
     } else {
       // complex list
       if (value != null && !(value instanceof List)) {
         throw new PropertyException(
             "Expected List value for: "
                 + name
                 + ", got "
                 + value.getClass().getName()
                 + " instead");
       }
       @SuppressWarnings("unchecked")
       List<Object> values = value == null ? Collections.emptyList() : (List<Object>) value;
       updateList(state, name, values, listType.getField());
     }
   }
 }
Beispiel #6
0
  /**
   * Gets the element data.
   *
   * @param element the element
   * @param type the type
   * @return the element data
   */
  @SuppressWarnings("unchecked")
  private static Object getElementData(org.dom4j.Element element, Type type, ServiceContext ctx)
      throws Exception {
    Object result = null;
    String dateStr = "";

    if (type.isSimpleType()) {
      if (isNuxeoDateType(type)) {
        String dateVal = element.getText();
        if (dateVal == null || dateVal.trim().isEmpty()) {
          result = type.decode("");
        } else {
          // Dates or date/times in any ISO 8601-based representations
          // directly supported by Nuxeo will be successfully decoded.
          result = type.decode(dateVal);
          // All other date or date/time values must first be converted
          // to a supported ISO 8601-based representation.
          if (result == null) {
            dateStr = DateTimeFormatUtils.toIso8601Timestamp(dateVal, ctx.getTenantId());
            if (dateStr != null) {
              result = type.decode(dateStr);
            } else {
              throw new IllegalArgumentException(
                  "Unrecognized date value '" + dateVal + "' in field '" + element.getName() + "'");
            }
          }
        }
      } else {
        String textValue = element.getText();
        if (textValue != null && textValue.trim().isEmpty()) {
          result = null;
        } else {
          result = type.decode(textValue);
        }
      }
    } else if (type.isListType()) {
      ListType ltype = (ListType) type;
      List<Object> list = new ArrayList<Object>();
      Iterator<org.dom4j.Element> it = element.elementIterator();
      while (it.hasNext()) {
        org.dom4j.Element el = it.next();
        list.add(getElementData(el, ltype.getFieldType(), ctx));
      }
      Type ftype = ltype.getFieldType();
      if (ftype.isSimpleType()) { // these are stored as arrays
        Class klass = JavaTypes.getClass(ftype);
        if (klass.isPrimitive()) {
          return PrimitiveArrays.toPrimitiveArray(list, klass);
        } else {
          return list.toArray((Object[]) Array.newInstance(klass, list.size()));
        }
      }
      result = list;
    } else {
      ComplexType ctype = (ComplexType) type;
      if (ctype.getName().equals(TypeConstants.CONTENT)) {
        //				String mimeType = element.elementText(ExportConstants.BLOB_MIME_TYPE);
        //				String encoding = element.elementText(ExportConstants.BLOB_ENCODING);
        //				String content = element.elementTextTrim(ExportConstants.BLOB_DATA);
        //				if ((content == null || content.length() == 0)
        //						&& (mimeType == null || mimeType.length() == 0)) {
        //					return null; // remove blob
        //				}
        //				Blob blob = null;
        //				if (xdoc.hasExternalBlobs()) {
        //					blob = xdoc.getBlob(content);
        //				}
        //				if (blob == null) { // may be the blob is embedded like a Base64
        //					// encoded data
        //					byte[] bytes = Base64.decode(content);
        //					blob = new StreamingBlob(new ByteArraySource(bytes));
        //				}
        //				blob.setMimeType(mimeType);
        //				blob.setEncoding(encoding);
        //				return blob;
      } else { // a complex type
        Map<String, Object> map = new HashMap<String, Object>();
        Iterator<org.dom4j.Element> it = element.elementIterator();
        while (it.hasNext()) {
          org.dom4j.Element el = it.next();
          String name = el.getName();
          Object value = getElementData(el, ctype.getField(el.getName()).getType(), ctx);
          map.put(name, value);
        }
        result = map;
      }
    }
    return result;
  }
Beispiel #7
0
  /**
   * Writes state from a complex property.
   *
   * <p>Writes only properties that are dirty.
   *
   * @return {@code true} if something changed
   */
  protected boolean writeComplexProperty(
      T state, ComplexProperty complexProperty, String xpath, WriteContext wc)
      throws PropertyException {
    @SuppressWarnings("unchecked")
    BlobWriteContext<T> writeContext = (BlobWriteContext<T>) wc;
    if (complexProperty instanceof BlobProperty) {
      Serializable value = ((BlobProperty) complexProperty).getValueForWrite();
      if (value != null && !(value instanceof Blob)) {
        throw new PropertyException("Cannot write a non-Blob value: " + value);
      }
      writeContext.recordBlob(state, (Blob) value, this);
      return true;
    }
    boolean changed = false;
    for (Property property : complexProperty) {
      // write dirty properties, but also phantoms with non-null default values
      // this is critical for DeltaLong updates to work, they need a non-null initial value
      if (property.isDirty()
          || (property.isPhantom() && property.getField().getDefaultValue() != null)) {
        // do the write
      } else {
        continue;
      }
      String name = property.getField().getName().getPrefixedName();
      name = internalName(name);
      if (checkReadOnlyIgnoredWrite(property, state)) {
        continue;
      }
      String xp = xpath == null ? name : xpath + '/' + name;
      writeContext.recordChange(xp);
      changed = true;

      Type type = property.getType();
      if (type.isSimpleType()) {
        // simple property
        Serializable value = property.getValueForWrite();
        state.setSingle(name, value);
        if (value instanceof Delta) {
          value = ((Delta) value).getFullValue();
          ((ScalarProperty) property).internalSetValue(value);
        }
      } else if (type.isComplexType()) {
        // complex property
        T childState = getChildForWrite(state, name, type);
        writeComplexProperty(childState, (ComplexProperty) property, xp, writeContext);
      } else {
        ListType listType = (ListType) type;
        if (listType.getFieldType().isSimpleType()) {
          // array
          Serializable value = property.getValueForWrite();
          if (value instanceof List) {
            List<?> list = (List<?>) value;
            Object[] array;
            if (list.isEmpty()) {
              array = new Object[0];
            } else {
              // use properly-typed array, useful for mem backend that doesn't re-convert all types
              Class<?> klass = list.get(0).getClass();
              array = (Object[]) Array.newInstance(klass, list.size());
            }
            value = list.toArray(array);
          } else if (value instanceof Object[]) {
            Object[] ar = (Object[]) value;
            if (ar.length != 0) {
              // use properly-typed array, useful for mem backend that doesn't re-convert all types
              Class<?> klass = Object.class;
              for (Object o : ar) {
                if (o != null) {
                  klass = o.getClass();
                  break;
                }
              }
              Object[] array;
              if (ar.getClass().getComponentType() == klass) {
                array = ar;
              } else {
                // copy to array with proper component type
                array = (Object[]) Array.newInstance(klass, ar.length);
                System.arraycopy(ar, 0, array, 0, ar.length);
              }
              value = array;
            }
          } else if (value == null) {
            // ok
          } else {
            throw new IllegalStateException(value.toString());
          }
          state.setArray(name, (Object[]) value);
        } else {
          // complex list
          // update it
          List<T> childStates = updateList(state, name, property);
          // write values
          int i = 0;
          for (Property childProperty : property.getChildren()) {
            T childState = childStates.get(i);
            String xpi = xp + '/' + i;
            boolean c =
                writeComplexProperty(
                    childState, (ComplexProperty) childProperty, xpi, writeContext);
            if (c) {
              writeContext.recordChange(xpi);
            }
            i++;
          }
        }
      }
    }
    return changed;
  }
Beispiel #8
0
  /** Sets a value (may be complex/list) into the document at the given xpath. */
  protected void setValueObject(T state, String xpath, Object value) throws PropertyException {
    xpath = canonicalXPath(xpath);
    String[] segments = xpath.split("/");

    ComplexType parentType = getType();
    for (int i = 0; i < segments.length; i++) {
      String segment = segments[i];
      Field field = parentType.getField(segment);
      if (field == null && i == 0) {
        // check facets
        SchemaManager schemaManager = Framework.getService(SchemaManager.class);
        for (String facet : getFacets()) {
          CompositeType facetType = schemaManager.getFacet(facet);
          field = facetType.getField(segment);
          if (field != null) {
            break;
          }
        }
      }
      if (field == null && i == 0 && getProxySchemas() != null) {
        // check proxy schemas
        for (Schema schema : getProxySchemas()) {
          field = schema.getField(segment);
          if (field != null) {
            break;
          }
        }
      }
      if (field == null) {
        throw new PropertyNotFoundException(xpath, i == 0 ? null : "Unknown segment: " + segment);
      }
      String name = field.getName().getPrefixedName(); // normalize from segment
      Type type = field.getType();

      // check if we have a complex list index in the next position
      if (i < segments.length - 1 && StringUtils.isNumeric(segments[i + 1])) {
        int index = Integer.parseInt(segments[i + 1]);
        i++;
        if (!type.isListType() || ((ListType) type).getFieldType().isSimpleType()) {
          throw new PropertyNotFoundException(xpath, "Cannot use index after segment: " + segment);
        }
        List<T> list = getChildAsList(state, name);
        if (index >= list.size()) {
          throw new PropertyNotFoundException(xpath, "Index out of bounds: " + index);
        }
        // find complex list state
        state = list.get(index);
        field = ((ListType) type).getField();
        if (i == segments.length - 1) {
          // last segment
          setValueComplex(state, field, value);
        } else {
          // not last segment
          parentType = (ComplexType) field.getType();
        }
        continue;
      }

      if (i == segments.length - 1) {
        // last segment
        setValueField(state, field, value);
      } else {
        // not last segment
        if (type.isSimpleType()) {
          // scalar
          throw new PropertyNotFoundException(xpath, "Segment must be last: " + segment);
        } else if (type.isComplexType()) {
          // complex property
          state = getChildForWrite(state, name, type);
          parentType = (ComplexType) type;
        } else {
          // list
          ListType listType = (ListType) type;
          if (listType.isArray()) {
            // array of scalars
            throw new PropertyNotFoundException(xpath, "Segment must be last: " + segment);
          } else {
            // complex list but next segment was not numeric
            throw new PropertyNotFoundException(
                xpath, "Missing list index after segment: " + segment);
          }
        }
      }
    }
  }
Beispiel #9
0
  /** Gets a value (may be complex/list) from the document at the given xpath. */
  protected Object getValueObject(T state, String xpath) throws PropertyException {
    xpath = canonicalXPath(xpath);
    String[] segments = xpath.split("/");

    /*
     * During this loop state may become null if we read an uninitialized complex property (DBS), in that case the
     * code must treat it as reading uninitialized values for its children.
     */
    ComplexType parentType = getType();
    for (int i = 0; i < segments.length; i++) {
      String segment = segments[i];
      Field field = parentType.getField(segment);
      if (field == null && i == 0) {
        // check facets
        SchemaManager schemaManager = Framework.getService(SchemaManager.class);
        for (String facet : getFacets()) {
          CompositeType facetType = schemaManager.getFacet(facet);
          field = facetType.getField(segment);
          if (field != null) {
            break;
          }
        }
      }
      if (field == null && i == 0 && getProxySchemas() != null) {
        // check proxy schemas
        for (Schema schema : getProxySchemas()) {
          field = schema.getField(segment);
          if (field != null) {
            break;
          }
        }
      }
      if (field == null) {
        throw new PropertyNotFoundException(xpath, i == 0 ? null : "Unknown segment: " + segment);
      }
      String name = field.getName().getPrefixedName(); // normalize from segment
      Type type = field.getType();

      // check if we have a complex list index in the next position
      if (i < segments.length - 1 && StringUtils.isNumeric(segments[i + 1])) {
        int index = Integer.parseInt(segments[i + 1]);
        i++;
        if (!type.isListType() || ((ListType) type).getFieldType().isSimpleType()) {
          throw new PropertyNotFoundException(xpath, "Cannot use index after segment: " + segment);
        }
        List<T> list = state == null ? Collections.emptyList() : getChildAsList(state, name);
        if (index >= list.size()) {
          throw new PropertyNotFoundException(xpath, "Index out of bounds: " + index);
        }
        // find complex list state
        state = list.get(index);
        parentType = (ComplexType) ((ListType) type).getFieldType();
        if (i == segments.length - 1) {
          // last segment
          return getValueComplex(state, parentType);
        } else {
          // not last segment
          continue;
        }
      }

      if (i == segments.length - 1) {
        // last segment
        return state == null ? null : getValueField(state, field);
      } else {
        // not last segment
        if (type.isSimpleType()) {
          // scalar
          throw new PropertyNotFoundException(xpath, "Segment must be last: " + segment);
        } else if (type.isComplexType()) {
          // complex property
          state = state == null ? null : getChild(state, name, type);
          // here state can be null (DBS), continue loop with it, meaning uninitialized for read
          parentType = (ComplexType) type;
        } else {
          // list
          ListType listType = (ListType) type;
          if (listType.isArray()) {
            // array of scalars
            throw new PropertyNotFoundException(xpath, "Segment must be last: " + segment);
          } else {
            // complex list but next segment was not numeric
            throw new PropertyNotFoundException(
                xpath, "Missing list index after segment: " + segment);
          }
        }
      }
    }
    throw new AssertionError("not reached");
  }
  protected void processDocAttributes(
      DocumentModel doc, Element el, AttributeConfigDescriptor conf) {
    String targetDocProperty = conf.getTargetDocProperty();

    if (log.isDebugEnabled()) {
      log.debug(
          String.format(
              MSG_UPDATE_PROPERTY,
              targetDocProperty,
              el.getUniquePath(),
              doc.getPathAsString(),
              doc.getType(),
              conf.toString()));
    }
    Property property = doc.getProperty(targetDocProperty);

    if (property.isScalar()) {
      Object value = resolveAndEvaluateXmlNode(el, conf.getSingleXpath());
      if (log.isTraceEnabled()) {
        log.trace(
            String.format(
                MSG_UPDATE_PROPERTY_TRACE,
                targetDocProperty,
                el.getUniquePath(),
                value,
                conf.toString()));
      }
      property.setValue(value);

    } else if (property.isComplex()) {

      if (property instanceof BlobProperty) {
        Object value = resolveBlob(el, conf);
        if (log.isTraceEnabled()) {
          log.trace(
              String.format(
                  MSG_UPDATE_PROPERTY_TRACE,
                  targetDocProperty,
                  el.getUniquePath(),
                  value,
                  conf.toString()));
        }
        property.setValue(value);
      } else {
        Object value = resolveComplex(el, conf);
        if (log.isTraceEnabled()) {
          log.trace(
              String.format(
                  MSG_UPDATE_PROPERTY_TRACE,
                  targetDocProperty,
                  el.getUniquePath(),
                  value,
                  conf.toString()));
        }
        property.setValue(value);
      }

    } else if (property.isList()) {

      ListType lType = (ListType) property.getType();

      Serializable value;

      if (lType.getFieldType().isSimpleType()) {
        value = (Serializable) resolveAndEvaluateXmlNode(el, conf.getSingleXpath());
        if (value != null) {
          Object values = property.getValue();
          if (values instanceof List) {
            ((List) values).add(value);
            property.setValue(values);
          } else if (values instanceof Object[]) {
            List<Object> valuesList = new ArrayList<>();
            Collections.addAll(valuesList, (Object[]) property.getValue());
            valuesList.add(value);
            property.setValue(valuesList.toArray());
          } else {
            log.error(
                "Simple multi value property "
                    + targetDocProperty
                    + " is neither a List nor an Array");
          }
        }
      } else {
        value = (Serializable) resolveComplex(el, conf);
        if (value != null && !conf.getMapping().isEmpty()) {
          property.addValue(value);
        }
      }

      if (log.isTraceEnabled()) {
        log.trace(
            String.format(
                MSG_UPDATE_PROPERTY_TRACE,
                targetDocProperty,
                el.getUniquePath(),
                value,
                conf.toString()));
      }
    }
  }