org.apache.olingo.ext.proxy.commons.InvokerInvocationHandler.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.olingo.ext.proxy.commons.InvokerInvocationHandler.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 org.apache.olingo.ext.proxy.commons;

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.olingo.client.api.communication.request.invoke.ClientNoContent;
import org.apache.olingo.client.api.uri.URIBuilder;
import org.apache.olingo.client.api.uri.URIFilter;
import org.apache.olingo.client.core.uri.URIUtils;
import org.apache.olingo.client.api.domain.ClientEntity;
import org.apache.olingo.client.api.domain.ClientEntitySet;
import org.apache.olingo.client.api.domain.ClientInvokeResult;
import org.apache.olingo.client.api.domain.ClientProperty;
import org.apache.olingo.client.api.domain.ClientValue;
import org.apache.olingo.commons.api.edm.EdmFunction;
import org.apache.olingo.commons.api.edm.EdmOperation;
import org.apache.olingo.commons.api.edm.EdmReturnType;
import org.apache.olingo.commons.api.edm.constants.EdmTypeKind;
import org.apache.olingo.commons.api.http.HttpMethod;
import org.apache.olingo.commons.core.edm.EdmTypeInfo;
import org.apache.olingo.ext.proxy.AbstractService;
import org.apache.olingo.ext.proxy.api.ComplexCollection;
import org.apache.olingo.ext.proxy.api.EntityCollection;
import org.apache.olingo.ext.proxy.api.OperationType;
import org.apache.olingo.ext.proxy.api.Operations;
import org.apache.olingo.ext.proxy.api.PrimitiveCollection;
import org.apache.olingo.ext.proxy.api.Sort;
import org.apache.olingo.ext.proxy.api.annotations.Operation;
import org.apache.olingo.ext.proxy.utils.ClassUtils;
import org.apache.olingo.ext.proxy.utils.CoreUtils;
import org.apache.olingo.ext.proxy.utils.ProxyUtils;

public class InvokerInvocationHandler<T, O extends Operations> extends AbstractInvocationHandler {

    private final URI baseURI;

    private URIBuilder uri;

    private final Map<String, ClientValue> parameters;

    private final Operation operation;

    private final EdmOperation edmOperation;

    protected final Class<T> targetRef;

    private final Class<?> operationRef;

    public InvokerInvocationHandler(final URI uri, final Map<String, ClientValue> parameters,
            final Operation operation, final EdmOperation edmOperation, final Type[] references,
            final AbstractService<?> service) {

        super(service);

        this.baseURI = uri;
        this.uri = this.baseURI == null ? null : service.getClient().newURIBuilder(this.baseURI.toASCIIString());
        this.parameters = parameters;
        this.operation = operation;
        this.edmOperation = edmOperation;
        if (references.length > 0) {
            this.targetRef = ClassUtils.<T>getTypeClass(references[0]);
            this.operationRef = references.length > 1 ? ClassUtils.<T>getTypeClass(references[1]) : null;
        } else {
            this.targetRef = null;
            this.operationRef = null;
        }
    }

    public Future<T> executeAsync() {
        return service.getClient().getConfiguration().getExecutor().submit(new Callable<T>() {

            @Override
            public T call() throws Exception {
                return execute();
            }
        });
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    public T execute() {
        if (operation == null || uri == null) {
            throw new IllegalStateException("Invalid operation");
        }

        try {
            // 1. IMPORTANT: flush any pending change *before* invoke if this operation is side effecting
            if (operation.type() == OperationType.ACTION) {
                service.getPersistenceManager().flush();
            }

            // 2. invoke
            final ClientInvokeResult result = service.getClient().getInvokeRequestFactory()
                    .getInvokeRequest(edmOperation instanceof EdmFunction ? HttpMethod.GET : HttpMethod.POST,
                            uri.build(), getResultReference(edmOperation.getReturnType()), parameters)
                    .execute().getBody();

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

            final EdmTypeInfo returnType = new EdmTypeInfo.Builder().setEdm(service.getClient().getCachedEdm())
                    .setTypeExpression(operation.returnType()).build();

            if (returnType.isEntityType()) {
                if (returnType.isCollection()) {
                    final Class<?> collItemType = ClassUtils.extractTypeArg(targetRef, EntityCollection.class);
                    return (T) ProxyUtils.getEntityCollectionProxy(service, collItemType, targetRef, null,
                            (ClientEntitySet) result, this.baseURI, false);
                } else {
                    return (T) ProxyUtils.getEntityProxy(service, (ClientEntity) result, null, targetRef, null,
                            false);
                }
            } else {
                Object res;

                final Class<?> ref = ClassUtils.getTypeClass(targetRef);
                final ClientProperty property = (ClientProperty) result;

                if (property == null || property.hasNullValue()) {
                    res = null;
                } else if (returnType.isCollection()) {
                    if (returnType.isComplexType()) {
                        final Class<?> itemRef = ClassUtils.extractTypeArg(ref, ComplexCollection.class);
                        final List items = new ArrayList();

                        for (ClientValue item : property.getValue().asCollection()) {
                            items.add(ProxyUtils.getComplexProxy(service, property.getName(), item, itemRef, null,
                                    null, true));
                        }

                        res = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
                                new Class<?>[] { ref },
                                new ComplexCollectionInvocationHandler(service, items, itemRef, null));
                    } else {
                        final List items = new ArrayList();

                        for (ClientValue item : property.getValue().asCollection()) {
                            items.add(item.asPrimitive().toValue());
                        }

                        res = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
                                new Class<?>[] { PrimitiveCollection.class },
                                new PrimitiveCollectionInvocationHandler(service, items, null, null));
                    }
                } else {
                    if (returnType.isComplexType()) {
                        res = ProxyUtils.getComplexProxy(service, property.getName(),
                                property.getValue().asComplex(), ref, null, null, false);
                    } else {
                        res = CoreUtils.getObjectFromODataValue(property.getValue(), targetRef, service);
                    }
                }

                return (T) res;
            }
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
    }

    @SuppressWarnings("unchecked")
    private <RES extends ClientInvokeResult> Class<RES> getResultReference(final EdmReturnType returnType) {
        Class<RES> result;

        if (returnType == null) {
            result = (Class<RES>) ClientNoContent.class;
        } else {
            if (returnType.isCollection() && returnType.getType().getKind() == EdmTypeKind.ENTITY) {
                result = (Class<RES>) ClientEntitySet.class;
            } else if (!returnType.isCollection() && returnType.getType().getKind() == EdmTypeKind.ENTITY) {
                result = (Class<RES>) ClientEntity.class;
            } else {
                result = (Class<RES>) ClientProperty.class;
            }
        }

        return result;
    }

    @Override
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if ("filter".equals(method.getName()) || "orderBy".equals(method.getName())
                || "top".equals(method.getName()) || "skip".equals(method.getName())
                || "expand".equals(method.getName()) || "select".equals(method.getName())) {
            invokeSelfMethod(method, args);
            return proxy;
        } else if ("operations".equals(method.getName()) && ArrayUtils.isEmpty(args)) {
            final EdmTypeInfo returnType = new EdmTypeInfo.Builder().setEdm(service.getClient().getCachedEdm())
                    .setTypeExpression(operation.returnType()).build();

            final URI prefixURI = URIUtils.buildFunctionInvokeURI(this.baseURI, parameters);

            OperationInvocationHandler handler;

            if (returnType.isComplexType()) {
                if (returnType.isCollection()) {
                    handler = OperationInvocationHandler.getInstance(new ComplexCollectionInvocationHandler(
                            targetRef, service, getClient().newURIBuilder(prefixURI.toASCIIString())));
                } else {
                    handler = OperationInvocationHandler.getInstance(ComplexInvocationHandler.getInstance(targetRef,
                            service, getClient().newURIBuilder(prefixURI.toASCIIString())));
                }
            } else {
                if (returnType.isCollection()) {
                    handler = OperationInvocationHandler.getInstance(new EntityCollectionInvocationHandler(service,
                            null, targetRef, null, getClient().newURIBuilder(prefixURI.toASCIIString())));
                } else {
                    handler = OperationInvocationHandler
                            .getInstance(EntityInvocationHandler.getInstance(prefixURI, targetRef, service));
                }
            }

            return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
                    new Class<?>[] { operationRef }, handler);
        } else if (isSelfMethod(method)) {
            return invokeSelfMethod(method, args);
        } else {
            throw new NoSuchMethodException(method.getName());
        }
    }

    public void filter(final String filter) {
        if (this.uri != null) {
            this.uri.filter(filter);
        }
    }

    public void filter(final URIFilter filter) {
        if (this.uri != null) {
            this.uri.filter(filter);
        }
    }

    public void orderBy(final Sort... sort) {
        if (this.uri != null) {
            final StringBuilder builder = new StringBuilder();
            for (Sort sortClause : sort) {
                builder.append(sortClause.getKey()).append(' ').append(sortClause.getValue()).append(',');
            }
            builder.deleteCharAt(builder.length() - 1);

            this.uri.orderBy(builder.toString());
        }
    }

    public void orderBy(final String orderBy) {
        if (this.uri != null) {
            this.uri.orderBy(orderBy);
        }
    }

    public void top(final int top) throws IllegalArgumentException {
        if (this.uri != null) {
            this.uri.top(top);
        }
    }

    public void skip(final int skip) throws IllegalArgumentException {
        if (this.uri != null) {
            this.uri.skip(skip);
        }
    }

    public void expand(final String... expand) {
        if (this.uri != null) {
            this.uri.expand(expand);
        }
    }

    public void select(final String... select) {
        if (this.uri != null) {
            this.uri.select(select);
        }
    }

    public void clearQueryOptions() {
        this.uri = this.baseURI == null ? null : getClient().newURIBuilder(baseURI.toASCIIString());
    }
}