File: InlineJavaPerlNatives.java

package info (click to toggle)
libinline-java-perl 0.67-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 716 kB
  • sloc: perl: 3,817; java: 2,621; makefile: 35; sh: 1
file content (231 lines) | stat: -rw-r--r-- 8,018 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
package org.perl.inline.java ;

import java.lang.reflect.* ;
import java.util.* ;
import java.io.* ;


public class InlineJavaPerlNatives extends InlineJavaPerlCaller {
	static private boolean inited = false ;
	static private Map<Class, Class> registered_classes = Collections.synchronizedMap(new HashMap<Class, Class>()) ;
	static private Map<String, String> registered_methods = Collections.synchronizedMap(new HashMap<String, String>()) ;


	protected InlineJavaPerlNatives() throws InlineJavaException {
		init() ;
		RegisterPerlNatives(this.getClass()) ;
	}


	static protected void init() throws InlineJavaException {
		init("install") ;
	}


	synchronized static protected void init(String mode) throws InlineJavaException {
		InlineJavaPerlCaller.init() ;
		if (! inited){
			try {
				String perlnatives_so = GetBundle().getString("inline_java_perlnatives_so_" + mode) ;
				File f = new File(perlnatives_so) ;
				if (! f.exists()){
					throw new InlineJavaException("Can't initialize PerlNatives " +
						"functionnality: PerlNatives extension (" + perlnatives_so + 
						") can't be found") ;
				}

				try {
					Class ste_class = Class.forName("java.lang.StackTraceElement") ;
				}
				catch (ClassNotFoundException cnfe){
					throw new InlineJavaException("Can't initialize PerlNatives " +
                        "functionnality: Java 1.4 or higher required (current is " +
						System.getProperty("java.version") + ").") ;
				}      	

				// Load the Natives shared object
				InlineJavaUtils.debug(2, "loading shared library " + perlnatives_so) ;
				System.load(perlnatives_so) ;

				inited = true ;
			}                                   
			catch (MissingResourceException mre){
				throw new InlineJavaException("Error loading InlineJava.properties resource: " + mre.getMessage()) ;
			}
		}
	}


	// This method actually does the real work of registering the methods.
	synchronized private void RegisterPerlNatives(Class c) throws InlineJavaException {
		if (registered_classes.get(c) == null){
			InlineJavaUtils.debug(3, "registering natives for class " + c.getName()) ;

			Constructor constructors[] = c.getDeclaredConstructors() ;
			Method methods[] = c.getDeclaredMethods() ;

			registered_classes.put(c, c) ;
			for (int i = 0 ; i < constructors.length ; i++){
				Constructor x = constructors[i] ;
				if (Modifier.isNative(x.getModifiers())){
					RegisterMethod(c, "new", x.getParameterTypes(), c) ;
				}
			}

			for (int i = 0 ; i < methods.length ; i++){
				Method x = methods[i] ;
				if (Modifier.isNative(x.getModifiers())){
					RegisterMethod(c, x.getName(), x.getParameterTypes(), x.getReturnType()) ;
				}
			}
		}
	}


	private void RegisterMethod(Class c, String mname, Class params[], Class rt) throws InlineJavaException {
		String cname = c.getName() ;
		InlineJavaUtils.debug(3, "registering native method " + mname + " for class " + cname) ;

		// Check return type
		if ((! Object.class.isAssignableFrom(rt))&&(rt != void.class)){
			throw new InlineJavaException("Perl native method " + mname + " of class " + cname + " can only have Object or void return types (not " + rt.getName() + ")") ;
		}

		// fmt starts with the return type, which for now is Object only (or void).
		StringBuffer fmt = new StringBuffer("L") ;
		StringBuffer sign = new StringBuffer("(") ;
		for (int i = 0 ; i < params.length ; i++){
			String code = InlineJavaClass.FindJNICode(params[i]) ;
			sign.append(code) ;
			char ch = code.charAt(0) ;
			char f = ch ;
			if (f == '['){
				// Arrays are Objects...
				f = 'L' ;
			}
			fmt.append(new String(new char [] {f})) ;
		}
		sign.append(")") ;

		sign.append(InlineJavaClass.FindJNICode(rt)) ;
		InlineJavaUtils.debug(3, "signature is " + sign) ;
		InlineJavaUtils.debug(3, "format is " + fmt) ;

		// For now, no method overloading so no signature necessary
		String meth = cname + "." + mname ;
		String prev = (String)registered_methods.get(meth) ;
		if (prev != null){
			throw new InlineJavaException("There already is a native method '" + mname + "' registered for class '" + cname + "'") ;
		}
		registered_methods.put(meth, fmt.toString()) ;

		// call the native method to hook it up
		RegisterMethod(c, mname, sign.toString()) ;
	}


	// This native method will call RegisterNative to hook up the magic
	// method implementation for the method.
	native private void RegisterMethod(Class c, String name, String signature) throws InlineJavaException ;


	// This method will be called from the native side. We need to figure
	// out who this method is and then look in up in the
	// registered method list and return the format.
	private String LookupMethod() throws InlineJavaException {
		InlineJavaUtils.debug(3, "entering LookupMethod") ;

		String caller[] = GetNativeCaller() ;
		String meth = caller[0] + "." + caller[1]  ;

		String fmt = (String)registered_methods.get(meth) ;
		if (fmt == null){
			throw new InlineJavaException("Native method " + meth + " is not registered") ;
		}

		InlineJavaUtils.debug(3, "exiting LookupMethod") ;

		return fmt ;
	}


	private Object InvokePerlMethod(Object args[]) throws InlineJavaException, InlineJavaPerlException {
		InlineJavaUtils.debug(3, "entering InvokePerlMethod") ;

		String caller[] = GetNativeCaller() ;
		String pkg = caller[0] ;
		String method = caller[1] ;

		// Transform the Java class name into the Perl package name
		StringTokenizer st = new StringTokenizer(pkg, ".") ;
		StringBuffer perl_sub = new StringBuffer() ;
		// Starting with "::" means that the package is relative to the caller package
		while (st.hasMoreTokens()){
			perl_sub.append("::" + st.nextToken()) ;
		}
		perl_sub.append("::" + method) ;

		for (int i = 0 ; i < args.length ; i++){
			InlineJavaUtils.debug(3, "InvokePerlMethod argument " + i + " = " + args[i]) ;
		}

		Object ret = CallPerlSub(perl_sub.toString(), args) ;

		InlineJavaUtils.debug(3, "exiting InvokePerlMethod") ;

		return ret ;
	}


	// This method must absolutely be called by a method DIRECTLY called
	// by generic_perl_native
	private String[] GetNativeCaller() throws InlineJavaException {
		InlineJavaUtils.debug(3, "entering GetNativeCaller") ;

		Class ste_class = null ;
		try {
			ste_class = Class.forName("java.lang.StackTraceElement") ;
		}
		catch (ClassNotFoundException cnfe){
			throw new InlineJavaException("Can't load class java.lang.StackTraceElement") ;
		}      	

		Throwable exec_point = new Throwable() ;
		try {
			Method m = exec_point.getClass().getMethod("getStackTrace", new Class [] {}) ;
			Object stack = m.invoke(exec_point, new Object [] {}) ;
			if (Array.getLength(stack) <= 2){
				throw new InlineJavaException("Improper use of InlineJavaPerlNatives.GetNativeCaller (call stack too short)") ;
			}

			Object ste = Array.get(stack, 2) ;
			m = ste.getClass().getMethod("isNativeMethod", new Class [] {}) ;
			Boolean is_nm = (Boolean)m.invoke(ste, new Object [] {}) ;
			if (! is_nm.booleanValue()){
				throw new InlineJavaException("Improper use of InlineJavaPerlNatives.GetNativeCaller (caller is not native)") ;
			}

			m = ste.getClass().getMethod("getClassName", new Class [] {}) ;
			String cname = (String)m.invoke(ste, new Object [] {}) ;
			m = ste.getClass().getMethod("getMethodName", new Class [] {}) ;
			String mname = (String)m.invoke(ste, new Object [] {}) ;

			InlineJavaUtils.debug(3, "exiting GetNativeCaller") ;

			return new String [] {cname, mname} ;
		}
		catch (NoSuchMethodException nsme){
			throw new InlineJavaException("Error manipulating java.lang.StackTraceElement classes: " +
				nsme.getMessage()) ;
		}
		catch (IllegalAccessException iae){
			throw new InlineJavaException("Error manipulating java.lang.StackTraceElement classes: " +
				iae.getMessage()) ;
		}
		catch (InvocationTargetException ite){
			// None of the methods invoked throw exceptions, so...
			throw new InlineJavaException("Exception caught while manipulating java.lang.StackTraceElement classes: " +
				ite.getTargetException()) ;
		}
	}
}