/* * Copyright (c) 2010-2016 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.marshaller; import com.evolveum.midpoint.prism.*; import com.evolveum.midpoint.prism.lex.LexicalProcessor; import com.evolveum.midpoint.prism.xnode.RootXNode; import com.evolveum.midpoint.util.exception.SchemaException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.xml.bind.JAXBElement; import javax.xml.namespace.QName; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** * @author mederly */ abstract class PrismParserImpl implements PrismParser { @NotNull private final ParserSource source; private final String language; @NotNull private final ParsingContext context; @NotNull private final PrismContextImpl prismContext; private final ItemDefinition<?> itemDefinition; private final QName itemName; private final QName typeName; private final Class<?> typeClass; //region Parameters ==================================================================================== PrismParserImpl(@NotNull ParserSource source, String language, @NotNull ParsingContext context, @NotNull PrismContextImpl prismContext, ItemDefinition<?> itemDefinition, QName itemName, QName typeName, Class<?> typeClass) { this.source = source; this.language = language; this.context = context; this.prismContext = prismContext; this.itemDefinition = itemDefinition; this.itemName = itemName; this.typeName = typeName; this.typeClass = typeClass; } private PrismParser create(ParserSource source, @Nullable String language, @NotNull ParsingContext context, PrismContextImpl prismContext, ItemDefinition<?> itemDefinition, QName itemName, QName typeName, Class<?> typeClass) { return source.throwsIOException() ? new PrismParserImplIO(source, language, context, prismContext, itemDefinition, itemName, typeName, typeClass) : new PrismParserImplNoIO(source, language, context, prismContext, itemDefinition, itemName, typeName, typeClass); } @NotNull @Override public PrismParser language(@Nullable String language) { return create(source, language, context, prismContext, itemDefinition, itemName, typeName, typeClass); } @NotNull @Override public PrismParser xml() { return language(PrismContext.LANG_XML); } @NotNull @Override public PrismParser json() { return language(PrismContext.LANG_JSON); } @NotNull @Override public PrismParser yaml() { return language(PrismContext.LANG_YAML); } @NotNull @Override public PrismParser context(@NotNull ParsingContext context) { return create(source, language, context, prismContext, itemDefinition, itemName, typeName, typeClass); } @NotNull @Override public PrismParser strict() { return create(source, language, context.clone().strict(), prismContext, itemDefinition, itemName, typeName, typeClass); } @NotNull @Override public PrismParser compat() { return create(source, language, context.clone().compat(), prismContext, itemDefinition, itemName, typeName, typeClass); } @NotNull @Override public PrismParser definition(ItemDefinition<?> itemDefinition) { return create(source, language, context, prismContext, itemDefinition, itemName, typeName, typeClass); } @NotNull @Override public PrismParser name(QName itemName) { return create(source, language, context, prismContext, itemDefinition, itemName, typeName, typeClass); } @NotNull @Override public PrismParser type(QName typeName) { return create(source, language, context, prismContext, itemDefinition, itemName, typeName, typeClass); } @NotNull @Override public PrismParser type(Class<?> typeClass) { return create(source, language, context, prismContext, itemDefinition, itemName, typeName, typeClass); } //endregion //region Parsing methods ==================================================================================== // interface @NotNull <O extends Objectable> PrismObject<O> doParse() throws SchemaException, IOException { RootXNode xnode = getLexicalProcessor().read(source, context); return prismContext.getPrismUnmarshaller().parseObject(xnode, itemDefinition, itemName, typeName, typeClass, context); } <IV extends PrismValue, ID extends ItemDefinition> Item<IV, ID> doParseItem() throws IOException, SchemaException { RootXNode xnode = getLexicalProcessor().read(source, context); return doParseItem(xnode, typeClass); } <IV extends PrismValue> IV doParseItemValue() throws IOException, SchemaException { RootXNode root = getLexicalProcessor().read(source, context); return doParseItemValue(root, typeClass); } <T> T doParseRealValue(Class<T> clazz) throws IOException, SchemaException { RootXNode root = getLexicalProcessor().read(source, context); return doParseRealValue(clazz, root); } @SuppressWarnings("unchecked") <T> T doParseRealValue() throws IOException, SchemaException { return (T) doParseRealValue(typeClass); } @SuppressWarnings("unchecked") <T> JAXBElement<T> doParseAnyValueAsJAXBElement() throws IOException, SchemaException { RootXNode root = getLexicalProcessor().read(source, context); T real = doParseRealValue(null, root); return real != null ? new JAXBElement<>(root.getRootElementName(), (Class<T>) real.getClass(), real) : null; } RootXNode doParseToXNode() throws IOException, SchemaException { return getLexicalProcessor().read(source, context); } @NotNull List<PrismObject<? extends Objectable>> doParseObjects() throws IOException, SchemaException { List<RootXNode> roots = getLexicalProcessor().readObjects(source, context); List<PrismObject<? extends Objectable>> objects = new ArrayList<>(); for (RootXNode root : roots) { PrismObject<? extends Objectable> object = prismContext.getPrismUnmarshaller() .parseObject(root, null, null, null, null, context); objects.add(object); } return objects; } Object doParseItemOrRealValue() throws IOException, SchemaException { RootXNode xnode = getLexicalProcessor().read(source, context); if (itemDefinition != null || itemName != null || typeName != null || typeClass != null) { throw new IllegalArgumentException("Item definition, item name, type name and type class must be null when calling parseItemOrRealValue."); } return prismContext.getPrismUnmarshaller().parseItemOrRealValue(xnode, context); } // implementation @SuppressWarnings("unchecked") private <IV extends PrismValue, ID extends ItemDefinition> Item<IV, ID> doParseItem(RootXNode xnode, Class<?> clazz) throws IOException, SchemaException { return (Item) prismContext.getPrismUnmarshaller().parseItem(xnode, itemDefinition, itemName, typeName, clazz, context); } private <IV extends PrismValue> IV doParseItemValue(RootXNode root, Class<?> clazz) throws IOException, SchemaException { Item<IV,?> item = doParseItem(root, clazz); return getSingleParentlessValue(item); } @Nullable private <IV extends PrismValue> IV getSingleParentlessValue(Item<IV, ?> item) { if (item.size() == 0) { return null; } else if (item.size() == 1) { IV value = item.getValues().get(0); value.setParent(null); return value; } else { throw new IllegalStateException("Expected one item value, got " + item.getValues().size() + " while parsing " + item); } } @SuppressWarnings("unchecked") private <T> T doParseRealValue(Class<T> clazz, RootXNode root) throws IOException, SchemaException { if (clazz == null) { ItemInfo info = ItemInfo.determine(itemDefinition, root.getRootElementName(), itemName, null, root.getTypeQName(), typeName, null, ItemDefinition.class, context, prismContext.getSchemaRegistry()); if (info.getItemDefinition() instanceof PrismContainerDefinition) { clazz = ((PrismContainerDefinition) info.getItemDefinition()).getCompileTimeClass(); } if (clazz == null && info.getTypeName() != null) { clazz = (Class) prismContext.getSchemaRegistry().determineClassForType(info.getTypeName()); } } // although bean unmarshaller can process containerables as well, prism unmarshaller is better at it if (clazz != null && !Containerable.class.isAssignableFrom(clazz) && getBeanUnmarshaller().canProcess(clazz)) { return getBeanUnmarshaller().unmarshal(root, clazz, context); } else if (clazz != null && Objectable.class.isAssignableFrom(clazz)) { // we need to NOT strip off OID PrismObject object = (PrismObject) doParseItem(root, clazz); return (T) object.asObjectable(); } else { PrismValue prismValue = doParseItemValue(root, clazz); if (prismValue == null) { return null; } else { return prismValue.getRealValue(); } } } private BeanUnmarshaller getBeanUnmarshaller() { return prismContext.getBeanUnmarshaller(); } @NotNull private LexicalProcessor<?> getLexicalProcessor() throws IOException { if (language != null) { return prismContext.getLexicalProcessorRegistry().processorFor(language); } else { return prismContext.getLexicalProcessorRegistry().findProcessor(source); } } //endregion }