1/*
2 * Copyright (c) 2009-2010 jMonkeyEngine
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 *   notice, this list of conditions and the following disclaimer.
11 *
12 * * Redistributions in binary form must reproduce the above copyright
13 *   notice, this list of conditions and the following disclaimer in the
14 *   documentation and/or other materials provided with the distribution.
15 *
16 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
17 *   may be used to endorse or promote products derived from this software
18 *   without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33package com.jme3.network.rmi;
34
35import com.jme3.network.HostedConnection;
36import java.lang.reflect.InvocationHandler;
37import java.lang.reflect.Method;
38import java.util.ArrayList;
39import java.util.HashMap;
40
41/**
42 * Contains various meta-data about an RMI interface.
43 *
44 * @author Kirill Vainer
45 */
46public class RemoteObject implements InvocationHandler {
47
48    /**
49     * Object ID
50     */
51    short objectId;
52
53    /**
54     * Contains {@link MethodDef method definitions} for all exposed
55     * RMI methods in the remote RMI interface.
56     */
57    MethodDef[] methodDefs;
58
59    /**
60     * Maps from methods locally retrieved from the RMI interface to
61     * a method ID.
62     */
63    HashMap<Method, Integer> methodMap = new HashMap<Method, Integer>();
64
65    /**
66     * The {@link ObjectStore} which stores this RMI interface.
67     */
68    ObjectStore store;
69
70    /**
71     * The client who exposed the RMI interface, or null if the server
72     * exposed it.
73     */
74    HostedConnection client;
75
76    public RemoteObject(ObjectStore store, HostedConnection client){
77        this.store = store;
78        this.client = client;
79    }
80
81    private boolean methodEquals(MethodDef methodDef, Method method){
82        Class<?>[] interfaceTypes = method.getParameterTypes();
83        Class<?>[] defTypes       = methodDef.paramTypes;
84
85        if (interfaceTypes.length == defTypes.length){
86            for (int i = 0; i < interfaceTypes.length; i++){
87                if (!defTypes[i].isAssignableFrom(interfaceTypes[i])){
88                    return false;
89                }
90            }
91            return true;
92        }
93        return false;
94    }
95
96    /**
97     * Generates mappings from the given interface into the remote RMI
98     * interface's implementation.
99     *
100     * @param interfaceClass The interface class to use.
101     */
102    public void loadMethods(Class<?> interfaceClass){
103        HashMap<String, ArrayList<Method>> nameToMethods
104                = new HashMap<String, ArrayList<Method>>();
105
106        for (Method method : interfaceClass.getDeclaredMethods()){
107            ArrayList<Method> list = nameToMethods.get(method.getName());
108            if (list == null){
109                list = new ArrayList<Method>();
110                nameToMethods.put(method.getName(), list);
111            }
112            list.add(method);
113        }
114
115        mapping_search: for (int i = 0; i < methodDefs.length; i++){
116            MethodDef methodDef = methodDefs[i];
117            ArrayList<Method> methods = nameToMethods.get(methodDef.name);
118            if (methods == null)
119                continue;
120
121            for (Method method : methods){
122                if (methodEquals(methodDef, method)){
123                    methodMap.put(method, i);
124                    continue mapping_search;
125                }
126            }
127        }
128    }
129
130    /**
131     * Callback from InvocationHandler.
132     */
133    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
134        return store.invokeRemoteMethod(this, method, args);
135    }
136
137}
138