/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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 org.apache.isis.schema.utils; import java.io.CharArrayWriter; import java.io.IOException; import java.io.PrintStream; import java.io.Reader; import java.io.StringReader; import java.io.Writer; import java.net.URL; import java.nio.charset.Charset; import java.util.Collections; import java.util.List; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import javax.xml.bind.Unmarshaller; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.io.Resources; import org.apache.isis.applib.services.bookmark.Bookmark; import org.apache.isis.applib.services.bookmark.BookmarkService; import org.apache.isis.applib.services.iactn.Interaction; import org.apache.isis.schema.cmd.v1.ParamDto; import org.apache.isis.schema.cmd.v1.ParamsDto; import org.apache.isis.schema.common.v1.InteractionType; import org.apache.isis.schema.common.v1.OidDto; import org.apache.isis.schema.common.v1.ValueDto; import org.apache.isis.schema.common.v1.ValueType; import org.apache.isis.schema.common.v1.ValueWithTypeDto; import org.apache.isis.schema.ixn.v1.ActionInvocationDto; import org.apache.isis.schema.ixn.v1.InteractionDto; import org.apache.isis.schema.ixn.v1.MemberExecutionDto; import org.apache.isis.schema.ixn.v1.PropertyEditDto; public final class InteractionDtoUtils { public static void init() { getJaxbContext(); } //region > marshalling static JAXBContext jaxbContext; static JAXBContext getJaxbContext() { if(jaxbContext == null) { try { jaxbContext = JAXBContext.newInstance(InteractionDto.class); } catch (JAXBException e) { throw new RuntimeException(e); } } return jaxbContext; } public static InteractionDto fromXml(final Reader reader) { try { final Unmarshaller un = getJaxbContext().createUnmarshaller(); return (InteractionDto) un.unmarshal(reader); } catch (JAXBException e) { throw new RuntimeException(e); } } public static InteractionDto fromXml(final String xml) { return fromXml(new StringReader(xml)); } public static InteractionDto fromXml( final Class<?> contextClass, final String resourceName, final Charset charset) throws IOException { final URL url = Resources.getResource(contextClass, resourceName); final String s = Resources.toString(url, charset); return fromXml(new StringReader(s)); } public static String toXml(final InteractionDto interactionDto) { final CharArrayWriter caw = new CharArrayWriter(); toXml(interactionDto, caw); return caw.toString(); } public static void toXml(final InteractionDto interactionDto, final Writer writer) { try { final Marshaller m = getJaxbContext().createMarshaller(); m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); m.marshal(interactionDto, writer); } catch (JAXBException e) { throw new RuntimeException(e); } } //endregion //region > newInteractionDto /** * Encapsulates the mechanism for obtaining a {@link MemberExecutionDto} DTO (XML memento) of the provided * in-memory {@link Interaction.Execution}. */ public enum Strategy { FLAT { @Override public MemberExecutionDto dtoFor(final Interaction.Execution<?, ?> execution) { return execution.getDto(); } }, DEEP { @Override public MemberExecutionDto dtoFor(final Interaction.Execution<?, ?> execution) { return traverse(execution); } private MemberExecutionDto traverse(final Interaction.Execution<?, ?> parentExecution) { final MemberExecutionDto parentDto = clone(parentExecution.getDto()); final List<Interaction.Execution<?, ?>> children = parentExecution.getChildren(); for (Interaction.Execution<?, ?> childExecution : children) { final MemberExecutionDto childDto = clone(childExecution.getDto()); final MemberExecutionDto.ChildExecutions childExecutions = InteractionDtoUtils.childExecutionsOf(parentDto); childExecutions.getExecution().add(childDto); traverse(childExecution); } return parentDto; } private MemberExecutionDto clone(final MemberExecutionDto memberExecutionDto) { return MemberExecutionDtoUtils.clone(memberExecutionDto); } //endregion }; public abstract MemberExecutionDto dtoFor(final Interaction.Execution<?, ?> execution); } private static MemberExecutionDto.ChildExecutions childExecutionsOf(final MemberExecutionDto dto) { MemberExecutionDto.ChildExecutions childExecutions = dto.getChildExecutions(); if(childExecutions == null) { childExecutions = new MemberExecutionDto.ChildExecutions(); dto.setChildExecutions(childExecutions); } return childExecutions; } /** * Creates a {@link InteractionDto} (serializable to XML) for the provided * {@link Interaction.Execution} (the applib object). */ public static InteractionDto newInteractionDto(final Interaction.Execution<?, ?> execution) { return newInteractionDto(execution, Strategy.FLAT); } /** * Creates a {@link InteractionDto} (serializable to XML) for the provided * {@link Interaction.Execution} (the applib object). */ public static InteractionDto newInteractionDto( final Interaction.Execution<?, ?> execution, final Strategy strategy) { final MemberExecutionDto memberExecutionDto = strategy.dtoFor(execution); return newInteractionDto(execution, memberExecutionDto); } private static InteractionDto newInteractionDto( final Interaction.Execution<?, ?> execution, final MemberExecutionDto executionDto) { final Interaction interaction = execution.getInteraction(); final String transactionId = interaction.getTransactionId().toString(); return InteractionDtoUtils.newInteractionDto(transactionId, executionDto); } private static InteractionDto newInteractionDto( final String transactionId, final MemberExecutionDto executionDto) { final InteractionDto interactionDto = new InteractionDto(); interactionDto.setMajorVersion("1"); interactionDto.setMinorVersion("0"); interactionDto.setTransactionId(transactionId); interactionDto.setExecution(executionDto); executionDto.setInteractionType( executionDto instanceof ActionInvocationDto ? InteractionType.ACTION_INVOCATION : InteractionType.PROPERTY_EDIT); return interactionDto; } //endregion //region > newActionInvocation, newPropertyModification public static ActionInvocationDto newActionInvocation( final int sequence, final Bookmark targetBookmark, final String targetTitle, final String actionIdentifier, final List<ParamDto> parameterDtos, final String user) { return (ActionInvocationDto) newMemberExecutionDto( InteractionType.ACTION_INVOCATION, sequence, targetBookmark, targetTitle, actionIdentifier, parameterDtos, null, user); } public static PropertyEditDto newPropertyEdit( final int sequence, final Bookmark targetBookmark, final String targetTitle, final String propertyIdentifier, final ValueWithTypeDto newValueDto, final String user) { return (PropertyEditDto) newMemberExecutionDto( InteractionType.PROPERTY_EDIT, sequence, targetBookmark, targetTitle, propertyIdentifier, null, newValueDto, user); } private static MemberExecutionDto newMemberExecutionDto( final InteractionType type, final int sequence, final Bookmark targetBookmark, final String targetTitle, final String memberId, final List<ParamDto> parameterDtos, final ValueWithTypeDto newValueDto, final String user) { final MemberExecutionDto executionDto; if(type == InteractionType.ACTION_INVOCATION) { final ActionInvocationDto invocation = new ActionInvocationDto(); final ParamsDto invocationParameters = parametersFor(invocation); invocation.setParameters(invocationParameters); invocationParameters.getParameter().addAll(parameterDtos); executionDto = invocation; } else { final PropertyEditDto edit = new PropertyEditDto(); edit.setNewValue(newValueDto); executionDto = edit; } executionDto.setSequence(sequence); final OidDto target = targetBookmark.toOidDto(); executionDto.setTarget(target); executionDto.setTitle(targetTitle); executionDto.setUser(user); executionDto.setMemberIdentifier(memberId); return executionDto; } //endregion //region > invocationFor, actionFor, timingsFor private static ActionInvocationDto actionInvocationFor(final InteractionDto interactionDto) { ActionInvocationDto invocation = (ActionInvocationDto) interactionDto.getExecution(); if(invocation == null) { invocation = new ActionInvocationDto(); interactionDto.setExecution(invocation); invocation.setInteractionType(InteractionType.ACTION_INVOCATION); } return invocation; } private static PropertyEditDto propertyEditFor(final InteractionDto interactionDto) { PropertyEditDto edit = (PropertyEditDto) interactionDto.getExecution(); if(edit == null) { edit = new PropertyEditDto(); interactionDto.setExecution(edit); edit.setInteractionType(InteractionType.PROPERTY_EDIT); } return edit; } private static List<ParamDto> parameterListFor(final InteractionDto ixnDto) { return parameterListFor(actionInvocationFor(ixnDto)); } private static ParamsDto parametersFor(final ActionInvocationDto invocationDto) { ParamsDto parameters = invocationDto.getParameters(); if(parameters == null) { parameters = new ParamsDto(); invocationDto.setParameters(parameters); } return parameters; } private static List<ParamDto> parameterListFor(final ActionInvocationDto invocationDto) { return parametersFor(invocationDto).getParameter(); } //endregion //region > addParamArg public static void addParamArg( final InteractionDto interactionDto, final String parameterName, final Class<?> parameterType, final Object arg, final BookmarkService bookmarkService) { final List<ParamDto> params = parameterListFor(interactionDto); ParamDto paramDto = CommonDtoUtils.newParamDto(parameterName, parameterType, arg, bookmarkService); params.add(paramDto); } //endregion //region > addReturn /** * * @param returnType - to determine the value type (if any) * @param result - either a value type (possibly boxed primitive), or a reference type * @param bookmarkService - used if not a value type */ public static void addReturn( final ActionInvocationDto invocationDto, final Class<?> returnType, final Object result, final BookmarkService bookmarkService) { final ValueWithTypeDto returned = CommonDtoUtils .newValueWithTypeDto(returnType, result, bookmarkService); invocationDto.setReturned(returned); } //endregion //region > getParameters, getParameterNames, getParameterTypes public static List<ParamDto> getParameters(final ActionInvocationDto ai) { final List<ParamDto> params = parameterListFor(ai); final int parameterNumber = getNumberOfParameters(ai); final List<ParamDto> paramDtos = Lists.newArrayList(); for (int i = 0; i < parameterNumber; i++) { final ParamDto paramDto = params.get(i); paramDtos.add(paramDto); } return Collections.unmodifiableList(paramDtos); } private static int getNumberOfParameters(final ActionInvocationDto ai) { final List<ParamDto> params = parameterListFor(ai); return params != null ? params.size() : 0; } public static List<String> getParameterNames(final ActionInvocationDto ai) { return immutableList(Iterables.transform(getParameters(ai), CommonDtoUtils.PARAM_DTO_TO_NAME)); } public static List<ValueType> getParameterTypes(final ActionInvocationDto ai) { return immutableList(Iterables.transform(getParameters(ai), CommonDtoUtils.PARAM_DTO_TO_TYPE)); } private static <T> List<T> immutableList(final Iterable<T> iterable) { return Collections.unmodifiableList(Lists.newArrayList(iterable)); } //endregion //region > getParameter, getParameterName, getParameterType, getParameterArgument public static ParamDto getParameter(final ActionInvocationDto ai, final int paramNum) { final int parameterNumber = getNumberOfParameters(ai); if(paramNum > parameterNumber) { throw new IllegalArgumentException(String.format("No such parameter %d (the memento has %d parameters)", paramNum, parameterNumber)); } final List<ParamDto> parameters = getParameters(ai); return parameters.get(paramNum); } public static ValueDto getParameterArgument(final ActionInvocationDto ai, final int paramNum) { return getParameter(ai, paramNum); } public static String getParameterName(final ActionInvocationDto ai, final int paramNum) { final ParamDto paramDto = getParameter(ai, paramNum); return paramDto.getName(); } public static ValueType getParameterType(final ActionInvocationDto ai, final int paramNum) { final ParamDto paramDto = getParameter(ai, paramNum); return paramDto.getType(); } public static boolean isNull(final ActionInvocationDto ai, int paramNum) { final ParamDto paramDto = getParameter(ai, paramNum); return paramDto.isNull(); } //endregion //region > getParameterArgValue public static <T> T getParameterArgValue(final ActionInvocationDto ai, int paramNum, Class<T> inferClass) { final ParamDto paramDto = getParameter(ai, paramNum); return CommonDtoUtils.getValue(paramDto); } public static <T> T getParameterArgValue(final ActionInvocationDto ai, int paramNum) { final ParamDto paramDto = getParameter(ai, paramNum); return CommonDtoUtils.getValue(paramDto); } //endregion //region > debugging (dump) public static void dump(final InteractionDto ixnDto, final PrintStream out) throws JAXBException { out.println(toXml(ixnDto)); } //endregion }