com.msopentech.odatajclient.proxy.api.impl.AbstractInvocationHandler.java Source code

Java tutorial

Introduction

Here is the source code for com.msopentech.odatajclient.proxy.api.impl.AbstractInvocationHandler.java

Source

/**
 * 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 com.msopentech.odatajclient.proxy.api.impl;

import com.msopentech.odatajclient.engine.client.ODataClient;
import com.msopentech.odatajclient.engine.client.ODataV3Client;
import com.msopentech.odatajclient.engine.data.ODataEntity;
import com.msopentech.odatajclient.engine.data.ODataEntitySet;
import com.msopentech.odatajclient.engine.data.ODataInvokeResult;
import com.msopentech.odatajclient.engine.data.ODataProperty;
import com.msopentech.odatajclient.engine.data.ODataValue;
import com.msopentech.odatajclient.engine.metadata.EdmType;
import com.msopentech.odatajclient.engine.metadata.EdmV3Type;
import com.msopentech.odatajclient.proxy.api.EntityContainerFactory;
import com.msopentech.odatajclient.proxy.api.annotations.Operation;
import com.msopentech.odatajclient.proxy.api.annotations.Parameter;
import com.msopentech.odatajclient.proxy.utils.ClassUtils;
import com.msopentech.odatajclient.proxy.utils.EngineUtils;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

abstract class AbstractInvocationHandler implements InvocationHandler {

    private static final long serialVersionUID = 358520026931462958L;

    protected final ODataV3Client client;

    protected EntityContainerInvocationHandler containerHandler;

    protected AbstractInvocationHandler(final ODataV3Client client,
            final EntityContainerInvocationHandler containerHandler) {

        this.client = client;
        this.containerHandler = containerHandler;
    }

    protected ODataV3Client getClient() {
        return client;
    }

    protected boolean isSelfMethod(final Method method, final Object[] args) {
        final Method[] selfMethods = getClass().getMethods();

        boolean result = false;

        for (int i = 0; i < selfMethods.length && !result; i++) {
            result = method.getName().equals(selfMethods[i].getName())
                    && Arrays.equals(method.getParameterTypes(), selfMethods[i].getParameterTypes());
        }

        return result;
    }

    protected Object invokeSelfMethod(final Method method, final Object[] args) throws NoSuchMethodException,
            IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        return getClass().getMethod(method.getName(), method.getParameterTypes()).invoke(this, args);
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    protected Object getEntityCollection(final Class<?> typeRef, final Class<?> typeCollectionRef,
            final String entityContainerName, final ODataEntitySet entitySet, final URI uri,
            final boolean checkInTheContext) {

        final List<Object> items = new ArrayList<Object>();

        for (ODataEntity entityFromSet : entitySet.getEntities()) {
            items.add(getEntityProxy(entityFromSet, entityContainerName, entitySet.getName(), typeRef,
                    checkInTheContext));
        }

        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
                new Class<?>[] { typeCollectionRef },
                new EntityCollectionInvocationHandler(containerHandler, items, typeRef, entityContainerName, uri));
    }

    protected <T> T getEntityProxy(final ODataEntity entity, final String entityContainerName,
            final String entitySetName, final Class<?> type, final boolean checkInTheContext) {

        return getEntityProxy(entity, entityContainerName, entitySetName, type, null, checkInTheContext);
    }

    @SuppressWarnings("unchecked")
    protected <T> T getEntityProxy(final ODataEntity entity, final String entityContainerName,
            final String entitySetName, final Class<?> type, final String eTag, final boolean checkInTheContext) {

        EntityTypeInvocationHandler handler = EntityTypeInvocationHandler.getInstance(entity, entityContainerName,
                entitySetName, type, containerHandler);

        if (StringUtils.isNotBlank(eTag)) {
            // override ETag into the wrapped object.
            handler.setETag(eTag);
        }

        if (checkInTheContext && EntityContainerFactory.getContext().entityContext().isAttached(handler)) {
            handler = EntityContainerFactory.getContext().entityContext().getEntity(handler.getUUID());
        }

        return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class<?>[] { type },
                handler);
    }

    protected Object functionImport(final Operation annotation, final Method method, final Object[] args,
            final URI target, final com.msopentech.odatajclient.engine.metadata.edm.v3.FunctionImport funcImp)
            throws InstantiationException, IllegalAccessException, NoSuchMethodException, IllegalArgumentException,
            InvocationTargetException {

        // 1. invoke params (if present)
        final Map<String, ODataValue> parameters = new HashMap<String, ODataValue>();
        if (!ArrayUtils.isEmpty(args)) {
            final Annotation[][] parAnnots = method.getParameterAnnotations();
            final Class<?>[] parTypes = method.getParameterTypes();

            for (int i = 0; i < args.length; i++) {
                if (!(parAnnots[i][0] instanceof Parameter)) {
                    throw new IllegalArgumentException("Paramter " + i + " is not annotated as @Param");
                }
                final Parameter parAnnot = (Parameter) parAnnots[i][0];

                if (!parAnnot.nullable() && args[i] == null) {
                    throw new IllegalArgumentException(
                            "Parameter " + parAnnot.name() + " is not nullable but a null value was provided");
                }

                final ODataValue paramValue = args[i] == null ? null
                        : EngineUtils.getODataValue(client, containerHandler.getFactory().getMetadata(),
                                new EdmV3Type(containerHandler.getFactory().getMetadata(), parAnnot.type()),
                                args[i]);

                parameters.put(parAnnot.name(), paramValue);
            }
        }

        // 2. IMPORTANT: flush any pending change *before* invoke if this operation is side effecting
        if (annotation.isSideEffecting()) {
            new Container(client, containerHandler.getFactory()).flush();
        }

        // 3. invoke
        final ODataInvokeResult result = client.getInvokeRequestFactory()
                .getInvokeRequest(target, containerHandler.getFactory().getMetadata(), funcImp, parameters)
                .execute().getBody();

        // 3. process invoke result
        if (StringUtils.isBlank(annotation.returnType())) {
            return ClassUtils.returnVoid();
        }

        final EdmType edmType = new EdmV3Type(containerHandler.getFactory().getMetadata(), annotation.returnType());
        if (edmType.isEnumType()) {
            throw new UnsupportedOperationException("Usupported enum type " + edmType.getTypeExpression());
        }
        if (edmType.isSimpleType() || edmType.isComplexType()) {
            return EngineUtils.getValueFromProperty(containerHandler.getFactory().getMetadata(),
                    (ODataProperty) result, method.getGenericReturnType());
        }
        if (edmType.isEntityType()) {
            if (edmType.isCollection()) {
                final ParameterizedType collType = (ParameterizedType) method.getReturnType()
                        .getGenericInterfaces()[0];
                final Class<?> collItemType = (Class<?>) collType.getActualTypeArguments()[0];
                return getEntityCollection(collItemType, method.getReturnType(), null, (ODataEntitySet) result,
                        target, false);
            } else {
                return getEntityProxy((ODataEntity) result, null, null, method.getReturnType(), false);
            }
        }

        throw new IllegalArgumentException("Could not process the functionImport information");
    }

    @Override
    public boolean equals(final Object obj) {
        return EqualsBuilder.reflectionEquals(this, obj);
    }

    @Override
    public int hashCode() {
        return HashCodeBuilder.reflectionHashCode(this);
    }

    @Override
    public String toString() {
        return ReflectionToStringBuilder.toString(this, ToStringStyle.MULTI_LINE_STYLE);
    }
}