Merge "Global cleanup of restconf client dependencies"
[yangtools.git] / restconf / restconf-client-impl / src / main / java / org / opendaylight / yangtools / restconf / client / BindingToRestRpc.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.yangtools.restconf.client;
9
10 import java.lang.reflect.InvocationHandler;
11 import java.lang.reflect.Method;
12 import java.lang.reflect.Proxy;
13 import java.util.ArrayList;
14 import java.util.List;
15
16 import org.opendaylight.yangtools.restconf.client.to.RestRpcError;
17 import org.opendaylight.yangtools.restconf.client.to.RestRpcResult;
18 import org.opendaylight.yangtools.restconf.common.ResourceUri;
19 import org.opendaylight.yangtools.restconf.utils.XmlTools;
20 import org.opendaylight.yangtools.yang.binding.BindingMapping;
21 import org.opendaylight.yangtools.yang.binding.DataContainer;
22 import org.opendaylight.yangtools.yang.binding.DataObject;
23 import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
24 import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
25 import org.opendaylight.yangtools.yang.common.RpcError;
26 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
27 import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
28 import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlDocumentUtils;
29 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
30 import org.opendaylight.yangtools.yang.model.api.Module;
31 import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
32 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35 import org.w3c.dom.Document;
36 import org.w3c.dom.ls.DOMImplementationLS;
37 import org.w3c.dom.ls.LSSerializer;
38
39 import com.google.common.base.Function;
40 import com.google.common.base.Optional;
41 import com.sun.jersey.api.client.ClientResponse;
42
43 public class BindingToRestRpc implements InvocationHandler {
44
45     private final RestconfClientImpl client;
46     private static final Logger logger = LoggerFactory.getLogger(BindingToRestRpc.class);
47     private final BindingIndependentMappingService mappingService;
48     private final SchemaContext schcemaContext;
49     private final Module module;
50
51     public BindingToRestRpc(Class<?> proxiedInterface,BindingIndependentMappingService mappingService,RestconfClientImpl client,SchemaContext schemaContext) throws Exception {
52         this.mappingService = mappingService;
53         this.client  = client;
54         this.schcemaContext = schemaContext;
55         YangModuleInfo moduleInfo = BindingReflections.getModuleInfo(proxiedInterface);
56         this.module = schemaContext.findModuleByName(moduleInfo.getName(),org.opendaylight.yangtools.yang.common.QName.parseRevision(moduleInfo.getRevision()));
57     }
58
59     @Override
60     public Object invoke(Object o,final Method method, Object[] objects) throws Throwable {
61         for (RpcDefinition rpcDef:module.getRpcs()){
62             if (method.getName().equals(BindingMapping.getMethodName(rpcDef.getQName()))){
63
64                 String moduleName = BindingReflections.getModuleInfo(method.getDeclaringClass()).getName();
65                 String rpcMethodName = rpcDef.getQName().getLocalName();
66                 Document rpcInputDoc = null;
67                 for (Object component:objects){
68                     CompositeNode rpcInput = mappingService.toDataDom((DataObject) component);
69                     rpcInputDoc = XmlDocumentUtils.toDocument(rpcInput,rpcDef.getInput(),XmlDocumentUtils.defaultValueCodecProvider());
70                 }
71                 DOMImplementationLS lsImpl = (DOMImplementationLS)rpcInputDoc.getImplementation().getFeature("LS", "3.0");
72                 LSSerializer serializer = lsImpl.createLSSerializer();
73                 serializer.getDomConfig().setParameter("xml-declaration", false);
74
75                 String payloadString = serializer.writeToString(rpcInputDoc);
76                 final Class<? extends DataContainer> desiredOutputClass = (Class<? extends DataContainer>)BindingReflections.resolveRpcOutputClass(method).get();
77                 final DataSchemaNode rpcOutputSchema = rpcDef.getOutput();
78                 return client.post(ResourceUri.OPERATIONS.getPath() + "/" + moduleName + ":" + rpcMethodName,payloadString,new Function<ClientResponse, Object>() {
79                     @Override
80                     public Object apply(ClientResponse clientResponse) {
81                         if (clientResponse.getStatus() != 200) {
82                             throw new IllegalStateException("Can't get data from restconf. "+clientResponse.getClientResponseStatus());
83                         }
84                         List<RpcError> errors =  new ArrayList<>();
85                         try {
86                             Document rpcOutputDocument = XmlTools.fromXml(clientResponse.getEntityInputStream());
87                             CompositeNode cn = (CompositeNode) XmlDocumentUtils.toDomNode(rpcOutputDocument.getDocumentElement(),
88                                     Optional.of(rpcOutputSchema),
89                                     Optional.of(XmlDocumentUtils.defaultValueCodecProvider()));
90                             DataContainer rpcOutputDataObject = mappingService.dataObjectFromDataDom(desiredOutputClass, cn);
91                             return new RestRpcResult(true,rpcOutputDataObject);
92                         } catch (Exception e) {
93                             logger.trace("Error while extracting rpc output in proxy method {}",e);
94                             RestRpcError error = new RestRpcError(RpcError.ErrorSeverity.ERROR, RpcError.ErrorType.APPLICATION,"Error while extracting rpc output in proxy method.",e);
95                         }
96                         return new RestRpcResult(false,errors);
97                     }
98                 });
99             }
100         }
101         throw new IllegalStateException("Unexpected state of proxy method.");
102     }
103
104     public static<T> T getProxy(Class<T> proxiedInterface,
105                                 BindingIndependentMappingService mappingService,
106                                 RestconfClientImpl restconfClient,
107                                 SchemaContext schemaContext) {
108         T proxiedType = null;
109         try {
110             proxiedType = (T) Proxy.newProxyInstance
111                     (BindingToRestRpc.class.getClassLoader(),
112                             new Class[]{proxiedInterface}, new BindingToRestRpc(proxiedInterface, mappingService, restconfClient, schemaContext));
113         } catch (Exception e) {
114             throw new IllegalStateException(e.getMessage());
115         }
116
117         return proxiedType;
118     }
119
120
121 }