com.evolveum.midpoint.prism.xjc.PrismForJAXBUtil.java Source code

Java tutorial

Introduction

Here is the source code for com.evolveum.midpoint.prism.xjc.PrismForJAXBUtil.java

Source

/*
 * Copyright (c) 2010-2015 Evolveum
 *
 * 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 com.evolveum.midpoint.prism.xjc;

import com.evolveum.midpoint.prism.*;
import com.evolveum.midpoint.prism.parser.DomParser;
import com.evolveum.midpoint.prism.parser.QueryConvertor;
import com.evolveum.midpoint.prism.polystring.PolyString;
import com.evolveum.midpoint.prism.query.ObjectFilter;
import com.evolveum.midpoint.prism.schema.SchemaRegistry;
import com.evolveum.midpoint.prism.xnode.MapXNode;
import com.evolveum.midpoint.prism.xnode.XNode;
import com.evolveum.midpoint.util.DOMUtil;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.util.exception.SystemException;
import com.evolveum.prism.xml.ns._public.query_3.SearchFilterType;
import com.evolveum.prism.xml.ns._public.types_3.ObjectType;
import com.evolveum.prism.xml.ns._public.types_3.PolyStringType;

import org.apache.commons.lang.Validate;
import org.w3c.dom.Element;

import javax.xml.bind.annotation.XmlAnyElement;
import javax.xml.namespace.QName;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map.Entry;

/**
 * @author lazyman
 */
public final class PrismForJAXBUtil {

    private PrismForJAXBUtil() {
    }

    public static <T> List<T> getPropertyValues(PrismContainer container, QName name, Class<T> clazz) {
        Validate.notNull(container, "Container must not be null.");
        Validate.notNull(name, "QName must not be null.");
        Validate.notNull(clazz, "Class type must not be null.");

        PrismProperty property;
        try {
            property = container.findOrCreateProperty(name);
        } catch (SchemaException e) {
            // This should not happen. Code generator and compiler should take care of that.
            throw new IllegalStateException("Internal schema error: " + e.getMessage(), e);
        }
        return new PropertyArrayList<T>(property);
    }

    public static <T> T getPropertyValue(PrismContainerValue container, QName name, Class<T> clazz) {
        Validate.notNull(container, "Container must not be null.");
        Validate.notNull(name, "QName must not be null.");
        Validate.notNull(clazz, "Class type must not be null.");

        PrismProperty property = container.findProperty(name);
        return getPropertyValue(property, clazz);
    }

    public static <T> T getPropertyValue(PrismContainer container, QName name, Class<T> clazz) {
        Validate.notNull(container, "Container must not be null.");
        Validate.notNull(name, "QName must not be null.");
        Validate.notNull(clazz, "Class type must not be null.");

        PrismProperty property = container.findProperty(name);
        return getPropertyValue(property, clazz);
    }

    private static <T> T getPropertyValue(PrismProperty<?> property, Class<T> requestedType) {
        if (property == null) {
            return null;
        }

        PrismPropertyValue<?> pvalue = property.getValue();
        if (pvalue == null) {
            return null;
        }

        Object propertyRealValue = pvalue.getValue();

        if (propertyRealValue instanceof Element) {
            if (requestedType.isAssignableFrom(Element.class)) {
                return (T) propertyRealValue;
            }
            Field anyField = getAnyField(requestedType);
            if (anyField == null) {
                throw new IllegalArgumentException("Attempt to read raw property " + property
                        + " while the requested class (" + requestedType + ") does not have 'any' field");
            }
            anyField.setAccessible(true);
            Collection<?> anyElementList = property.getRealValues();
            T requestedTypeInstance;
            try {
                requestedTypeInstance = requestedType.newInstance();
                anyField.set(requestedTypeInstance, anyElementList);
            } catch (InstantiationException e) {
                throw new IllegalArgumentException("Instantiate error while reading raw property " + property
                        + ", requested class (" + requestedType + "):" + e.getMessage(), e);
            } catch (IllegalAccessException e) {
                throw new IllegalArgumentException(
                        "Illegal access error while reading raw property " + property + ", requested class ("
                                + requestedType + ")" + ", field " + anyField + ": " + e.getMessage(),
                        e);
            }
            return requestedTypeInstance;
        }

        return JaxbTypeConverter.mapPropertyRealValueToJaxb(propertyRealValue);
    }

    private static <T> Field getAnyField(Class<T> clazz) {
        for (Field field : clazz.getDeclaredFields()) {
            XmlAnyElement xmlAnyElementAnnotation = field.getAnnotation(XmlAnyElement.class);
            if (xmlAnyElementAnnotation != null) {
                return field;
            }
        }
        return null;
    }

    public static <T> List<T> getPropertyValues(PrismContainerValue container, QName name, Class<T> clazz) {
        Validate.notNull(container, "Container must not be null.");
        Validate.notNull(name, "QName must not be null.");
        Validate.notNull(clazz, "Class type must not be null.");

        PrismProperty property;
        try {
            property = container.findOrCreateProperty(name);
        } catch (SchemaException e) {
            // This should not happen. Code generator and compiler should take care of that.
            throw new IllegalStateException("Internal schema error: " + e.getMessage(), e);
        }
        return new PropertyArrayList<T>(property);
    }

    public static <T> void setPropertyValue(PrismContainerValue<?> container, QName name, T value) {
        Validate.notNull(container, "Container must not be null.");
        Validate.notNull(name, "QName must not be null.");

        if (value == null) {
            container.removeProperty(name);
        } else {
            PrismProperty<?> property;
            try {
                property = container.findOrCreateProperty(name);
            } catch (SchemaException e) {
                // This should not happen. Code generator and compiler should take care of that.
                throw new IllegalStateException("Internal schema error: " + e.getMessage(), e);
            }
            Object propertyRealValue = JaxbTypeConverter.mapJaxbToPropertyRealValue(value);
            if (propertyRealValue == null) {
                container.removeProperty(name);
            } else {
                property.setValue(new PrismPropertyValue(propertyRealValue));
            }
        }
    }

    public static <T> void setPropertyValue(PrismContainer container, QName name, T value) {
        setPropertyValue(container.getValue(), name, value);
    }

    public static <T extends Containerable> PrismContainerValue<T> getFieldContainerValue(PrismContainer<?> parent,
            QName fieldName) {
        Validate.notNull(parent, "Container must not be null.");
        Validate.notNull(fieldName, "Field QName must not be null.");

        return getFieldContainerValue(parent.getValue(), fieldName);
    }

    public static <T extends Containerable> PrismContainerValue<T> getFieldContainerValue(
            PrismContainerValue<?> parent, QName fieldName) {
        Validate.notNull(parent, "Container value must not be null.");
        Validate.notNull(fieldName, "Field QName must not be null.");

        PrismContainer<T> container = parent.findItem(fieldName, PrismContainer.class);
        return container != null ? container.getValue() : null;
    }

    public static <T extends Containerable> T getFieldSingleContainerable(PrismContainerValue<?> parent,
            QName fieldName, Class<T> fieldClass) {
        PrismContainerValue<T> fieldContainerValue = getFieldContainerValue(parent, fieldName);
        if (fieldContainerValue == null) {
            return null;
        }
        return fieldContainerValue.asContainerable(fieldClass);
    }

    public static <T extends PrismContainer<?>> T getContainer(PrismContainerValue parentValue, QName name) {
        Validate.notNull(parentValue, "Parent container value must not be null.");
        Validate.notNull(name, "QName must not be null.");

        try {
            return (T) parentValue.findOrCreateContainer(name);
        } catch (SchemaException ex) {
            throw new SystemException(ex.getMessage(), ex);
        }
    }

    public static <T extends PrismContainer<?>> T getContainer(PrismContainer<?> parent, QName name) {
        Validate.notNull(parent, "Container must not be null.");
        Validate.notNull(name, "QName must not be null.");

        try {
            return (T) parent.findOrCreateContainer(name);
        } catch (SchemaException ex) {
            throw new SystemException(ex.getMessage(), ex);
        }
    }

    public static <T extends Containerable> boolean setFieldContainerValue(PrismContainerValue<?> parent,
            QName fieldName, PrismContainerValue<T> fieldContainerValue) {
        Validate.notNull(parent, "Prism container value must not be null.");
        Validate.notNull(fieldName, "QName must not be null.");

        try {
            PrismContainer<T> fieldContainer = null;
            if (fieldContainerValue == null) {
                parent.removeContainer(fieldName);
            } else {
                if (fieldContainerValue.getParent() != null && fieldContainerValue.getParent() != parent) {
                    // This value is already part of another prism. We need to clone it to add it here.
                    fieldContainerValue = fieldContainerValue.clone();
                }
                fieldContainer = new PrismContainer<T>(fieldName, parent.getPrismContext());
                fieldContainer.add(fieldContainerValue);
                if (parent.getParent() == null) {
                    parent.add(fieldContainer);
                } else {
                    parent.addReplaceExisting(fieldContainer);
                }
            }
            //           // Make sure that the definition from parent is applied to new field container
            //           if (fieldContainer.getDefinition() == null) {
            //              PrismContainer<?> parentContainer = parent.getContainer();
            //              if (parentContainer != null) {
            //                 PrismContainerDefinition<?> parentDefinition = parentContainer.getDefinition();
            //                 if (parentDefinition != null) {
            //                    PrismContainerDefinition<T> fieldDefinition = parentDefinition.findContainerDefinition(fieldName);
            //                    fieldContainer.setDefinition(fieldDefinition);
            //                 }
            //              }
            //           }
        } catch (SchemaException e) {
            // This should not happen. Code generator and compiler should take care of that.
            throw new IllegalStateException("Internal schema error: " + e.getMessage(), e);
        }
        return true;
    }

    public static boolean setFieldContainerValue(PrismContainer<?> parent, QName fieldName,
            PrismContainerValue<?> fieldContainerValue) {
        return setFieldContainerValue(parent.getValue(), fieldName, fieldContainerValue);
    }

    public static PrismReferenceValue getReferenceValue(PrismContainerValue<?> parent, QName name) {
        Validate.notNull(parent, "Prism container value must not be null.");
        Validate.notNull(name, "QName must not be null.");

        PrismReference reference = parent.findItem(name, PrismReference.class);
        return reference != null ? reference.getValue() : null;
    }

    public static PrismReferenceValue getReferenceValue(PrismContainer parent, QName name) {
        Validate.notNull(parent, "Prism container must not be null.");
        Validate.notNull(name, "QName must not be null.");

        PrismReference reference = getReference(parent, name);
        return reference != null ? reference.getValue() : null;
    }

    public static PrismReference getReference(PrismContainer parent, QName name) {
        Validate.notNull(parent, "Prism container must not be null.");
        Validate.notNull(name, "QName must not be null.");

        return parent.findReference(name);
    }

    /**
     * This method must merge new value with potential existing value of the reference.
     * E.g. it is possible to call setResource(..) and then setResourceRef(..) with the
     * same OID. In that case the result should be one reference that has both OID/type/filter
     * and object.
     * Assumes single-value reference
     */
    public static void setReferenceValueAsRef(PrismContainerValue<?> parentValue, QName referenceName,
            PrismReferenceValue value) {
        Validate.notNull(parentValue, "Prism container value must not be null.");
        Validate.notNull(referenceName, "QName must not be null.");

        PrismReference reference;
        try {
            reference = parentValue.findOrCreateItem(referenceName, PrismReference.class);
        } catch (SchemaException e) {
            // This should not happen. Code generator and compiler should take care of that.
            throw new IllegalStateException("Internal schema error: " + e.getMessage(), e);
        }
        if (reference == null) {
            throw new IllegalArgumentException("No reference " + referenceName + " in " + parentValue);
        }
        if (value == null) {
            parentValue.remove(reference);
        } else {
            if (reference.isEmpty()) {
                if (value.getParent() != null) {
                    value = value.clone();
                }
                reference.add(value);
            } else {
                reference.getValue().setOid(value.getOid());
                reference.getValue().setTargetType(value.getTargetType());
                reference.getValue().setFilter(value.getFilter());
                reference.getValue().setDescription(value.getDescription());
            }
        }
    }

    public static void setReferenceValueAsRef(PrismContainer parent, QName name, PrismReferenceValue value) {
        setReferenceValueAsRef(parent.getValue(), name, value);
    }

    /**
     * This method must merge new value with potential existing value of the reference.
     * E.g. it is possible to call setResource(..) and then setResourceRef(..) with the
     * same OID. In that case the result should be one reference that has both OID/type/filter
     * and object.
     * Assumes single-value reference
     */
    public static void setReferenceValueAsObject(PrismContainerValue parentValue, QName referenceQName,
            PrismObject targetObject) {
        Validate.notNull(parentValue, "Prism container value must not be null.");
        Validate.notNull(referenceQName, "QName must not be null.");

        PrismReference reference;
        try {
            reference = parentValue.findOrCreateReference(referenceQName);
        } catch (SchemaException e) {
            // This should not happen. Code generator and compiler should take care of that.
            throw new IllegalStateException("Internal schema error: " + e.getMessage(), e);
        }
        if (reference == null) {
            throw new IllegalArgumentException("No reference " + referenceQName + " in " + parentValue);
        }
        PrismReferenceValue referenceValue = reference.getValue();
        referenceValue.setObject(targetObject);
    }

    // Assumes single-value reference
    public static void setReferenceValueAsObject(PrismContainer parent, QName referenceQName,
            PrismObject targetObject) {
        setReferenceValueAsObject(parent.getValue(), referenceQName, targetObject);
    }

    public static <T extends Objectable> PrismReferenceValue objectableAsReferenceValue(T objectable,
            PrismReference reference) {
        PrismObject<T> object = objectable.asPrismObject();
        for (PrismReferenceValue refValue : reference.getValues()) {
            if (object == refValue.getObject()) {
                return refValue;
            }
        }
        PrismReferenceValue referenceValue = new PrismReferenceValue();
        referenceValue.setObject(object);
        return referenceValue;
    }

    public static <T extends Containerable> List<PrismContainerValue<T>> getContainerValues(
            PrismContainerValue<T> parent, QName name, Class<T> clazz) {
        return getContainerValues(parent.getContainer(), name, clazz);
    }

    public static <T extends Containerable> List<PrismContainerValue<T>> getContainerValues(
            PrismContainer<T> parent, QName name, Class<T> clazz) {
        Validate.notNull(parent, "Container must not be null.");
        Validate.notNull(name, "QName must not be null.");

        PrismContainer container;
        try {
            container = parent.findOrCreateContainer(name);
        } catch (SchemaException e) {
            // This should not happen. Code generator and compiler should take care of that.
            throw new IllegalStateException("Internal schema error: " + e.getMessage(), e);
        }
        return container.getValues();
    }

    public static <T> List<T> getAny(PrismContainerValue value, Class<T> clazz) {
        return new AnyArrayList(value);
    }

    public static PrismObject setupContainerValue(PrismObject prismObject, PrismContainerValue containerValue) {
        PrismContainerable parent = containerValue.getParent();
        if (parent != null && parent instanceof PrismObject) {
            return (PrismObject) parent;
        }
        try {
            prismObject.setValue(containerValue);
            return prismObject;
        } catch (SchemaException e) {
            // This should not happen. Code generator and compiler should take care of that.
            throw new IllegalStateException("Internal schema error: " + e.getMessage(), e);
        }
    }

    public static PrismReference getReference(PrismContainerValue parent, QName fieldName) {
        try {
            return parent.findOrCreateReference(fieldName);
        } catch (SchemaException e) {
            // This should not happen. Code generator and compiler should take care of that.
            throw new IllegalStateException("Internal schema error: " + e.getMessage(), e);
        }
    }

    public static void setReferenceFilterClauseXNode(PrismReferenceValue rval, SearchFilterType filterType) {
        if (filterType != null) {
            rval.setFilter(filterType.clone());
        } else {
            rval.setFilter(null);
        }
    }

    public static MapXNode getReferenceFilterClauseXNode(PrismReferenceValue rval) {
        SearchFilterType filter = rval.getFilter();
        if (filter == null || !filter.containsFilterClause()) {
            return null;
        }
        return filter.getFilterClauseXNode();
    }

    public static PolyStringType getReferenceTargetName(PrismReferenceValue rval) {
        PolyString targetName = rval.getTargetName();
        if (targetName == null) {
            return null;
        }
        return new PolyStringType(targetName);
    }

    public static void setReferenceTargetName(PrismReferenceValue rval, PolyStringType name) {
        if (name == null) {
            rval.setTargetName((PolyString) null);
        } else {
            rval.setTargetName(name.toPolyString());
        }
    }

    private static DomParser getDomParser(PrismValue pval) {
        PrismContext prismContext = pval.getPrismContext();
        if (prismContext != null) {
            return prismContext.getParserDom();
        } else {
            DomParser parser = new DomParser(null);
            return parser;
        }
    }

    public static <T extends ObjectType> T createTargetInstance(PrismReferenceValue value) {
        try {
            return (T) value.getTargetTypeCompileTimeClass().newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            throw new SystemException("Cannot instantiate item: " + e.getMessage(), e);
        }
    }
}