1 package org.perl.inline.java ;
2 
3 import java.util.* ;
4 import java.io.* ;
5 import java.lang.reflect.* ;
6 
7 
8 /*
9 	This is where most of the work of Inline Java is done. Here determine
10 	the request type and then we proceed to serve it.
11 */
12 class InlineJavaProtocol {
13 	private InlineJavaServer ijs ;
14 	private InlineJavaClass ijc ;
15 	private InlineJavaArray ija ;
16 	private String cmd ;
17 	private String response = null ;
18 
19 	private final String encoding = "UTF-8" ;
20 
21 	static private Map member_cache = Collections.synchronizedMap(new HashMap()) ;
22 	static private final String report_version = "V2" ;
23 
InlineJavaProtocol(InlineJavaServer _ijs, String _cmd)24 	InlineJavaProtocol(InlineJavaServer _ijs, String _cmd) {
25 		ijs = _ijs ;
26 		ijc = new InlineJavaClass(ijs, this) ;
27 		ija = new InlineJavaArray(ijc) ;
28 
29 		cmd = _cmd ;
30 	}
31 
32 
33 	/*
34 		Starts the analysis of the command line
35 	*/
Do()36 	void Do() throws InlineJavaException {
37 		StringTokenizer st = new StringTokenizer(cmd, " ") ;
38 		String c = st.nextToken() ;
39 
40 		if (c.equals("call_method")){
41 			CallJavaMethod(st) ;
42 		}
43 		else if (c.equals("set_member")){
44 			SetJavaMember(st) ;
45 		}
46 		else if (c.equals("get_member")){
47 			GetJavaMember(st) ;
48 		}
49 		else if (c.equals("add_classpath")){
50 			AddClassPath(st) ;
51 		}
52 		else if (c.equals("server_type")){
53 			ServerType(st) ;
54 		}
55 		else if (c.equals("report")){
56 			Report(st) ;
57 		}
58 		else if (c.equals("isa")){
59 			IsA(st) ;
60 		}
61 		else if (c.equals("create_object")){
62 			CreateJavaObject(st) ;
63 		}
64 		else if (c.equals("delete_object")){
65 			DeleteJavaObject(st) ;
66 		}
67 		else if (c.equals("obj_cnt")){
68 			ObjectCount(st) ;
69 		}
70 		else if (c.equals("cast")){
71 			Cast(st) ;
72 		}
73 		else if (c.equals("read")){
74 			Read(st) ;
75 		}
76 		else if (c.equals("make_buffered")){
77 			MakeBuffered(st) ;
78 		}
79 		else if (c.equals("readline")){
80 			ReadLine(st) ;
81 		}
82 		else if (c.equals("write")){
83 			Write(st) ;
84 		}
85 		else if (c.equals("close")){
86 			Close(st) ;
87 		}
88 		else if (c.equals("die")){
89 			InlineJavaUtils.debug(1, "received a request to die...") ;
90 			ijs.Shutdown() ;
91 		}
92 		else {
93 			throw new InlineJavaException("Unknown command " + c) ;
94 		}
95 	}
96 
97 	/*
98 		Returns a report on the Java classes, listing all public methods
99 		and members
100 	*/
Report(StringTokenizer st)101 	void Report(StringTokenizer st) throws InlineJavaException {
102 		StringBuffer pw = new StringBuffer(report_version + "\n") ;
103 
104 		StringTokenizer st2 = new StringTokenizer(st.nextToken(), ":") ;
105 		st2.nextToken() ;
106 
107 		StringTokenizer st3 = new StringTokenizer(Decode(st2.nextToken()), " ") ;
108 
109 		ArrayList class_list = new ArrayList() ;
110 		while (st3.hasMoreTokens()){
111 			String c = st3.nextToken() ;
112 			class_list.add(class_list.size(), c) ;
113 		}
114 
115 		for (int i = 0 ; i < class_list.size() ; i++){
116 			String name = (String)class_list.get(i) ;
117 			Class c = ijc.ValidateClass(name) ;
118 
119 			InlineJavaUtils.debug(3, "reporting for " + c) ;
120 
121 			Class parent = c.getSuperclass() ;
122 			String pname = (parent == null ? "null" : parent.getName()) ;
123 			pw.append("class " + c.getName() + " " + pname + "\n") ;
124 			Constructor constructors[] = c.getConstructors() ;
125 			Method methods[] = c.getMethods() ;
126 			Field fields[] = c.getFields() ;
127 
128 			boolean pub = ijc.ClassIsPublic(c) ;
129 			if (pub){
130 				// If the class is public and has no constructors,
131 				// we provide a default no-arg constructors.
132 				if (c.getDeclaredConstructors().length == 0){
133 					String noarg_sign = InlineJavaUtils.CreateSignature(new Class [] {}) ;
134 					pw.append("constructor " + noarg_sign + "\n") ;
135 				}
136 			}
137 
138 			boolean pn = InlineJavaPerlNatives.class.isAssignableFrom(c) ;
139 			for (int j = 0 ; j < constructors.length ; j++){
140 				Constructor x = constructors[j] ;
141 				if ((pn)&&(Modifier.isNative(x.getModifiers()))){
142 					continue ;
143 				}
144 				Class params[] = x.getParameterTypes() ;
145 				String sign = InlineJavaUtils.CreateSignature(params) ;
146 				Class decl = x.getDeclaringClass() ;
147 				pw.append("constructor " + sign + "\n") ;
148 			}
149 
150 			for (int j = 0 ; j < methods.length ; j++){
151 				Method x = methods[j] ;
152 				if ((pn)&&(Modifier.isNative(x.getModifiers()))){
153 					continue ;
154 				}
155 				String stat = (Modifier.isStatic(x.getModifiers()) ? " static " : " instance ") ;
156 				String sign = InlineJavaUtils.CreateSignature(x.getParameterTypes()) ;
157 				Class decl = x.getDeclaringClass() ;
158 				pw.append("method" + stat + decl.getName() + " " + x.getName() + sign + "\n") ;
159 			}
160 
161 			for (int j = 0 ; j < fields.length ; j++){
162 				Field x = fields[(InlineJavaUtils.ReverseMembers() ? (fields.length - 1 - j) : j)] ;
163 				String stat = (Modifier.isStatic(x.getModifiers()) ? " static " : " instance ") ;
164 				Class decl = x.getDeclaringClass() ;
165 				Class type = x.getType() ;
166 				pw.append("field" + stat + decl.getName() + " " + x.getName() + " " + type.getName() + "\n") ;
167 			}
168 		}
169 
170 		SetResponse(pw.toString()) ;
171 	}
172 
173 
AddClassPath(StringTokenizer st)174 	void AddClassPath(StringTokenizer st) throws InlineJavaException {
175 		while (st.hasMoreTokens()){
176 			String path = Decode(st.nextToken()) ;
177 			InlineJavaServer.GetInstance().GetUserClassLoader().AddClassPath(path) ;
178 		}
179 		SetResponse(null) ;
180 	}
181 
182 
ServerType(StringTokenizer st)183 	void ServerType(StringTokenizer st) throws InlineJavaException {
184 		SetResponse(ijs.GetType()) ;
185 	}
186 
187 
IsA(StringTokenizer st)188 	void IsA(StringTokenizer st) throws InlineJavaException {
189 		String class_name = st.nextToken() ;
190 		Class c = ijc.ValidateClass(class_name) ;
191 
192 		String is_it_a = st.nextToken() ;
193 		Class d = ijc.ValidateClass(is_it_a) ;
194 
195 		SetResponse(new Integer(ijc.DoesExtend(c, d))) ;
196 	}
197 
198 
ObjectCount(StringTokenizer st)199 	void ObjectCount(StringTokenizer st) throws InlineJavaException {
200 		SetResponse(new Integer(ijs.ObjectCount())) ;
201 	}
202 
203 
204 	/*
205 		Creates a Java Object with the specified arguments.
206 	*/
CreateJavaObject(StringTokenizer st)207 	void CreateJavaObject(StringTokenizer st) throws InlineJavaException {
208 		String class_name = st.nextToken() ;
209 		Class c = ijc.ValidateClass(class_name) ;
210 
211 		if (! ijc.ClassIsArray(c)){
212 			ArrayList f = ValidateMethod(true, c, class_name, st) ;
213 			Object p[] = (Object [])f.get(1) ;
214 			Class clist[] = (Class [])f.get(2) ;
215 
216 			try {
217 				Object o = CreateObject(c, p, clist) ;
218 				SetResponse(o) ;
219 			}
220 			catch (InlineJavaInvocationTargetException ite){
221 				Throwable t = ite.GetThrowable() ;
222 				if (t instanceof InlineJavaException){
223 					InlineJavaException ije = (InlineJavaException)t ;
224 					throw ije ;
225 				}
226 				else{
227 					SetResponse(new InlineJavaThrown(t)) ;
228 				}
229 			}
230 		}
231 		else{
232 			// Here we send the type of array we want, but CreateArray
233 			// exception the element type.
234 			StringBuffer sb = new StringBuffer(class_name) ;
235 			// Remove the ['s
236 			while (sb.toString().startsWith("[")){
237 				sb.replace(0, 1, "") ;
238 			}
239 			// remove the L and the ;
240 			if (sb.toString().startsWith("L")){
241 				sb.replace(0, 1, "") ;
242 				sb.replace(sb.length() - 1, sb.length(), "") ;
243 			}
244 
245 			Class ec = ijc.ValidateClass(sb.toString()) ;
246 
247 			InlineJavaUtils.debug(4, "array elements: " + ec.getName()) ;
248 			Object o = ija.CreateArray(ec, st) ;
249 			SetResponse(o) ;
250 		}
251 	}
252 
253 
254 	/*
255 		Calls a Java method
256 	*/
CallJavaMethod(StringTokenizer st)257 	void CallJavaMethod(StringTokenizer st) throws InlineJavaException {
258 		int id = Integer.parseInt(st.nextToken()) ;
259 
260 		String class_name = st.nextToken() ;
261 		Object o = null ;
262 		if (id > 0){
263 			o = ijs.GetObject(id) ;
264 
265 			// Use the class sent by Perl (it might be casted)
266 			// class_name = o.getClass().getName() ;
267 		}
268 
269 		Class c = ijc.ValidateClass(class_name) ;
270 		String method = st.nextToken() ;
271 
272 		if ((ijc.ClassIsArray(c))&&(method.equals("getLength"))){
273 			int length = Array.getLength(o) ;
274 			SetResponse(new Integer(length)) ;
275 		}
276 		else{
277 			ArrayList f = ValidateMethod(false, c, method, st) ;
278 			Method m = (Method)f.get(0) ;
279 			String name = m.getName() ;
280 			Object p[] = (Object [])f.get(1) ;
281 
282 			try {
283 				Object ret = InlineJavaServer.GetInstance().GetUserClassLoader().invoke(m, o, p) ;
284 				SetResponse(ret, AutoCast(ret, m.getReturnType())) ;
285 			}
286 			catch (IllegalAccessException e){
287 				throw new InlineJavaException("You are not allowed to invoke method " + name + " in class " + class_name + ": " + e.getMessage()) ;
288 			}
289 			catch (IllegalArgumentException e){
290 				throw new InlineJavaException("Arguments for method " + name + " in class " + class_name + " are incompatible: " + e.getMessage()) ;
291 			}
292 			catch (InvocationTargetException e){
293 				Throwable t = e.getTargetException() ;
294 				String type = t.getClass().getName() ;
295 				String msg = t.getMessage() ;
296 				InlineJavaUtils.debug(1, "method " + name + " in class " + class_name + " threw exception " + type + ": " + msg) ;
297 				if (t instanceof InlineJavaException){
298 					InlineJavaException ije = (InlineJavaException)t ;
299 					throw ije ;
300 				}
301 				else{
302 					SetResponse(new InlineJavaThrown(t)) ;
303 				}
304 			}
305 		}
306 	}
307 
308 
309 	/*
310 	*/
AutoCast(Object o, Class want)311 	Class AutoCast(Object o, Class want){
312 		if (o == null){
313 			return null ;
314 		}
315 		else {
316 			Class got = o.getClass() ;
317 			if (got.equals(want)){
318 				return null ;
319 			}
320 			else {
321 				boolean _public = (got.getModifiers() & Modifier.PUBLIC) != 0 ;
322 				if ((_public)||(got.getPackage() == null)){
323 					return null ;
324 				}
325 				else {
326 					InlineJavaUtils.debug(3, "AutoCast: " + got.getName() + " -> " + want.getName()) ;
327 					return want ;
328 				}
329 			}
330 		}
331 	}
332 
333 
334 	/*
335 		Returns a new reference to the current object, using the provided subtype
336 	*/
Cast(StringTokenizer st)337 	void Cast(StringTokenizer st) throws InlineJavaException {
338 		int id = Integer.parseInt(st.nextToken()) ;
339 
340 		String class_name = st.nextToken() ;
341 		Object o = ijs.GetObject(id) ;
342 		Class c = ijc.ValidateClass(class_name) ;
343 
344 		SetResponse(o, c) ;
345 	}
346 
347 
348 	/*
349 	*/
Read(StringTokenizer st)350 	void Read(StringTokenizer st) throws InlineJavaException {
351 		int id = Integer.parseInt(st.nextToken()) ;
352 		int len = Integer.parseInt(st.nextToken()) ;
353 
354 		Object o = ijs.GetObject(id) ;
355 		Object ret = null ;
356 		try {
357 			ret = InlineJavaHandle.read(o, len) ;
358 		}
359 		catch (java.io.IOException e){
360 			ret = new InlineJavaThrown(e) ;
361 		}
362 
363 		SetResponse(ret) ;
364 	}
365 
366 
MakeBuffered(StringTokenizer st)367 	void MakeBuffered(StringTokenizer st) throws InlineJavaException {
368 		int id = Integer.parseInt(st.nextToken()) ;
369 
370 		Object o = ijs.GetObject(id) ;
371 		Object ret = null ;
372 		try {
373 			ret = InlineJavaHandle.makeBuffered(o) ;
374 			if (ret != o){
375 				int buf_id = ijs.PutObject(ret) ;
376 				ret = new Integer(buf_id) ;
377 			}
378 			else {
379 				ret = new Integer(id) ;
380 			}
381 		}
382 		catch (java.io.IOException e){
383 			ret = new InlineJavaThrown(e) ;
384 		}
385 
386 		SetResponse(ret) ;
387 	}
388 
389 
ReadLine(StringTokenizer st)390 	void ReadLine(StringTokenizer st) throws InlineJavaException {
391 		int id = Integer.parseInt(st.nextToken()) ;
392 
393 		Object o = ijs.GetObject(id) ;
394 		Object ret = null ;
395 		try {
396 			ret = InlineJavaHandle.readLine(o) ;
397 		}
398 		catch (java.io.IOException e){
399 			ret = new InlineJavaThrown(e) ;
400 		}
401 
402 		SetResponse(ret) ;
403 	}
404 
405 
Write(StringTokenizer st)406 	void Write(StringTokenizer st) throws InlineJavaException {
407 		int id = Integer.parseInt(st.nextToken()) ;
408 		Object arg = ijc.CastArgument(Object.class, st.nextToken()) ;
409 
410 		Object o = ijs.GetObject(id) ;
411 		Object ret = null ;
412 		try {
413 			int len = InlineJavaHandle.write(o, arg.toString()) ;
414 			ret = new Integer(len) ;
415 		}
416 		catch (java.io.IOException e){
417 			ret = new InlineJavaThrown(e) ;
418 		}
419 
420 		SetResponse(ret) ;
421 	}
422 
423 
Close(StringTokenizer st)424 	void Close(StringTokenizer st) throws InlineJavaException {
425 		int id = Integer.parseInt(st.nextToken()) ;
426 
427 		Object o = ijs.GetObject(id) ;
428 		Object ret = null ;
429 		try {
430 			InlineJavaHandle.close(o) ;
431 		}
432 		catch (java.io.IOException e){
433 			ret = new InlineJavaThrown(e) ;
434 		}
435 
436 		SetResponse(ret) ;
437 	}
438 
439 
440 	/*
441 		Sets a Java member variable
442 	*/
SetJavaMember(StringTokenizer st)443 	void SetJavaMember(StringTokenizer st) throws InlineJavaException {
444 		int id = Integer.parseInt(st.nextToken()) ;
445 
446 		String class_name = st.nextToken() ;
447 		Object o = null ;
448 		if (id > 0){
449 			o = ijs.GetObject(id) ;
450 
451 			// Use the class sent by Perl (it might be casted)
452 			// class_name = o.getClass().getName() ;
453 		}
454 
455 		Class c = ijc.ValidateClass(class_name) ;
456 		String member = st.nextToken() ;
457 
458 		if (ijc.ClassIsArray(c)){
459 			int idx = Integer.parseInt(member) ;
460 			Class type = ijc.ValidateClass(st.nextToken()) ;
461 			String arg = st.nextToken() ;
462 
463 			String msg = "For array of type " + c.getName() + ", element " + member + ": " ;
464 			try {
465 				Object elem = ijc.CastArgument(type, arg) ;
466 				InlineJavaServer.GetInstance().GetUserClassLoader().array_set(o, idx, elem) ;
467 				SetResponse(null) ;
468 			}
469 			catch (InlineJavaCastException e){
470 				throw new InlineJavaCastException(msg + e.getMessage()) ;
471 			}
472 			catch (InlineJavaException e){
473 				throw new InlineJavaException(msg + e.getMessage()) ;
474 			}
475 		}
476 		else{
477 			ArrayList fl = ValidateMember(c, member, st) ;
478 			Field f = (Field)fl.get(0) ;
479 			String name = f.getName() ;
480 			Object p = (Object)fl.get(1) ;
481 
482 			try {
483 				InlineJavaServer.GetInstance().GetUserClassLoader().set(f, o, p) ;
484 				SetResponse(null) ;
485 			}
486 			catch (IllegalAccessException e){
487 				throw new InlineJavaException("You are not allowed to set member " + name + " in class " + class_name + ": " + e.getMessage()) ;
488 			}
489 			catch (IllegalArgumentException e){
490 				throw new InlineJavaException("Argument for member " + name + " in class " + class_name + " is incompatible: " + e.getMessage()) ;
491 			}
492 		}
493 	}
494 
495 
496 	/*
497 		Gets a Java member variable
498 	*/
GetJavaMember(StringTokenizer st)499 	void GetJavaMember(StringTokenizer st) throws InlineJavaException {
500 		int id = Integer.parseInt(st.nextToken()) ;
501 
502 		String class_name = st.nextToken() ;
503 		Object o = null ;
504 		if (id > 0){
505 			o = ijs.GetObject(id) ;
506 
507 			// Use the class sent by Perl (it might be casted)
508 			// class_name = o.getClass().getName() ;
509 		}
510 
511 		Class c = ijc.ValidateClass(class_name) ;
512 		String member = st.nextToken() ;
513 
514 		if (ijc.ClassIsArray(c)){
515 			int idx = Integer.parseInt(member) ;
516 			Object ret = InlineJavaServer.GetInstance().GetUserClassLoader().array_get(o, idx) ;
517 			Class eclass = ijc.ValidateClass(ijc.CleanClassName(class_name.substring(1))) ;
518 			SetResponse(ret, AutoCast(ret, eclass)) ;
519 		}
520 		else{
521 			ArrayList fl = ValidateMember(c, member, st) ;
522 
523 			Field f = (Field)fl.get(0) ;
524 			String name = f.getName() ;
525 			try {
526 				Object ret = InlineJavaServer.GetInstance().GetUserClassLoader().get(f, o) ;
527 				SetResponse(ret, AutoCast(ret, f.getType())) ;
528 			}
529 			catch (IllegalAccessException e){
530 				throw new InlineJavaException("You are not allowed to set member " + name + " in class " + class_name + ": " + e.getMessage()) ;
531 			}
532 			catch (IllegalArgumentException e){
533 				throw new InlineJavaException("Argument for member " + name + " in class " + class_name + " is incompatible: " + e.getMessage()) ;
534 			}
535 		}
536 	}
537 
538 
539 	/*
540 		Deletes a Java object
541 	*/
DeleteJavaObject(StringTokenizer st)542 	void DeleteJavaObject(StringTokenizer st) throws InlineJavaException {
543 		int id = Integer.parseInt(st.nextToken()) ;
544 
545 		Object o = ijs.DeleteObject(id) ;
546 
547 		SetResponse(null) ;
548 	}
549 
550 
551 	/*
552 		Creates a Java Object with the specified arguments.
553 	*/
CreateObject(Class p, Object args[], Class proto[])554 	Object CreateObject(Class p, Object args[], Class proto[]) throws InlineJavaException {
555 		p = ijc.FindWrapper(p) ;
556 
557 		String name = p.getName() ;
558 		Object ret = null ;
559 		try {
560 			ret = InlineJavaServer.GetInstance().GetUserClassLoader().create(p, args, proto) ;
561 		}
562 		catch (NoSuchMethodException e){
563 			throw new InlineJavaException("Constructor for class " + name + " with signature " + InlineJavaUtils.CreateSignature(proto) + " not found: " + e.getMessage()) ;
564 		}
565 		catch (InstantiationException e){
566 			throw new InlineJavaException("You are not allowed to instantiate object of class " + name + ": " + e.getMessage()) ;
567 		}
568 		catch (IllegalAccessException e){
569 			throw new InlineJavaException("You are not allowed to instantiate object of class " + name + " using the constructor with signature " + InlineJavaUtils.CreateSignature(proto) + ": " + e.getMessage()) ;
570 		}
571 		catch (IllegalArgumentException e){
572 			throw new InlineJavaException("Arguments to constructor for class " + name + " with signature " + InlineJavaUtils.CreateSignature(proto) + " are incompatible: " + e.getMessage()) ;
573 		}
574 		catch (InvocationTargetException e){
575 			Throwable t = e.getTargetException() ;
576 			String type = t.getClass().getName() ;
577 			String msg = t.getMessage() ;
578 			throw new InlineJavaInvocationTargetException(
579 				"Constructor for class " + name + " with signature " + InlineJavaUtils.CreateSignature(proto) + " threw exception " + type + ": " + msg,
580 				t) ;
581 		}
582 
583 		return ret ;
584 	}
585 
586 
587 	/*
588 		Makes sure a method exists
589 	*/
ValidateMethod(boolean constructor, Class c, String name, StringTokenizer st)590 	ArrayList ValidateMethod(boolean constructor, Class c, String name, StringTokenizer st) throws InlineJavaException {
591 		ArrayList ret = new ArrayList() ;
592 
593 		// Extract signature
594 		String signature = st.nextToken() ;
595 
596 		// Extract the arguments
597 		ArrayList args = new ArrayList() ;
598 		while (st.hasMoreTokens()){
599 			args.add(args.size(), st.nextToken()) ;
600 		}
601 
602 		String key = c.getName() + "." + name + signature ;
603 		ArrayList ml = new ArrayList() ;
604 		Class params[] = null ;
605 
606 		Member cached = (Member)member_cache.get(key) ;
607 		if (cached != null){
608 				InlineJavaUtils.debug(3, "method was cached") ;
609 				ml.add(ml.size(), cached) ;
610 		}
611 		else{
612 			Member ma[] = (constructor ? (Member [])c.getConstructors() : (Member [])c.getMethods()) ;
613 			for (int i = 0 ; i < ma.length ; i++){
614 				Member m = ma[i] ;
615 
616 				if (m.getName().equals(name)){
617 					InlineJavaUtils.debug(3, "found a " + name + (constructor ? " constructor" : " method")) ;
618 
619 					if (constructor){
620 						params = ((Constructor)m).getParameterTypes() ;
621 					}
622 					else{
623 						params = ((Method)m).getParameterTypes() ;
624 					}
625 
626 					// Now we check if the signatures match
627 					String sign = InlineJavaUtils.CreateSignature(params, ",") ;
628 					InlineJavaUtils.debug(3, sign + " = " + signature + "?") ;
629 
630 					if (signature.equals(sign)){
631 						InlineJavaUtils.debug(3, "has matching signature " + sign) ;
632 						ml.add(ml.size(), m) ;
633 						member_cache.put(key, m) ;
634 						break ;
635 					}
636 				}
637 			}
638 		}
639 
640 		// Now we got a list of matching methods (actually 0 or 1).
641 		// We have to figure out which one we will call.
642 		if (ml.size() == 0){
643 			// Nothing matched. Maybe we got a default constructor
644 			if ((constructor)&&(signature.equals("()"))){
645 				ret.add(0, null) ;
646 				ret.add(1, new Object [] {}) ;
647 				ret.add(2, new Class [] {}) ;
648 			}
649 			else{
650 				throw new InlineJavaException(
651 					(constructor ? "Constructor " : "Method ") +
652 					name + " for class " + c.getName() + " with signature " +
653 					signature + " not found") ;
654 			}
655 		}
656 		else if (ml.size() == 1){
657 			// Now we need to force the arguments received to match
658 			// the methods signature.
659 			Member m = (Member)ml.get(0) ;
660 			if (constructor){
661 				params = ((Constructor)m).getParameterTypes() ;
662 			}
663 			else{
664 				params = ((Method)m).getParameterTypes() ;
665 			}
666 
667 			String msg = "In method " + name + " of class " + c.getName() + ": " ;
668 			try {
669 				ret.add(0, m) ;
670 				ret.add(1, ijc.CastArguments(params, args)) ;
671 				ret.add(2, params) ;
672 			}
673 			catch (InlineJavaCastException e){
674 				throw new InlineJavaCastException(msg + e.getMessage()) ;
675 			}
676 			catch (InlineJavaException e){
677 				throw new InlineJavaException(msg + e.getMessage()) ;
678 			}
679 		}
680 
681 		return ret ;
682 	}
683 
684 
685 	/*
686 		Makes sure a member exists
687 	*/
ValidateMember(Class c, String name, StringTokenizer st)688 	ArrayList ValidateMember(Class c, String name, StringTokenizer st) throws InlineJavaException {
689 		ArrayList ret = new ArrayList() ;
690 
691 		// Extract member type
692 		String type = st.nextToken() ;
693 
694 		// Extract the argument
695 		String arg = st.nextToken() ;
696 
697 		String key = type + " " + c.getName() + "." + name ;
698 		ArrayList fl = new ArrayList() ;
699 		Class param = null ;
700 
701 		Member cached = (Member)member_cache.get(key) ;
702 		if (cached != null){
703 			InlineJavaUtils.debug(3, "member was cached") ;
704 			fl.add(fl.size(), cached) ;
705 		}
706 		else {
707 			Field fa[] = c.getFields() ;
708 			for (int i = 0 ; i < fa.length ; i++){
709 				Field f = fa[(InlineJavaUtils.ReverseMembers() ? (fa.length - 1 - i) : i)] ;
710 
711 				if (f.getName().equals(name)){
712 					InlineJavaUtils.debug(3, "found a " + name + " member") ;
713 
714 					param = f.getType() ;
715 					String t = param.getName() ;
716 					if (type.equals(t)){
717 						InlineJavaUtils.debug(3, "has matching type " + t) ;
718 						fl.add(fl.size(), f) ;
719 					}
720 				}
721 			}
722 		}
723 
724 		// Now we got a list of matching members.
725 		// We have to figure out which one we will call.
726 		if (fl.size() == 0){
727 			throw new InlineJavaException(
728 				"Member " + name + " of type " + type + " for class " + c.getName() +
729 					" not found") ;
730 		}
731 		else {
732 			// Now we need to force the arguments received to match
733 			// the methods signature.
734 
735 			// If we have more that one, we use the last one, which is the most
736 			// specialized
737 			Field f = (Field)fl.get(fl.size() - 1) ;
738 			member_cache.put(key, f) ;
739 			param = f.getType() ;
740 
741 			String msg = "For member " + name + " of class " + c.getName() + ": " ;
742 			try {
743 				ret.add(0, f) ;
744 				ret.add(1, ijc.CastArgument(param, arg)) ;
745 				ret.add(2, param) ;
746 			}
747 			catch (InlineJavaCastException e){
748 				throw new InlineJavaCastException(msg + e.getMessage()) ;
749 			}
750 			catch (InlineJavaException e){
751 				throw new InlineJavaException(msg + e.getMessage()) ;
752 			}
753 		}
754 
755 		return ret ;
756 	}
757 
758 
759 	/*
760 		This sets the response that will be returned to the Perl
761 		script
762 	*/
SetResponse(Object o)763 	void SetResponse(Object o) throws InlineJavaException {
764 		SetResponse(o, null) ;
765 	}
766 
767 
SetResponse(Object o, Class p)768 	void SetResponse(Object o, Class p) throws InlineJavaException {
769 		response = "ok " + SerializeObject(o, p) ;
770 	}
771 
772 
SerializeObject(Object o, Class p)773 	String SerializeObject(Object o, Class p) throws InlineJavaException {
774 		Class c = (o == null ? null : o.getClass()) ;
775 
776 		if ((c != null)&&(p != null)){
777 			if (ijc.DoesExtend(c, p) < 0){
778 				throw new InlineJavaException("Can't cast a " + c.getName() + " to a " + p.getName()) ;
779 			}
780 			else{
781 				c = p ;
782 			}
783 		}
784 
785 		if (o == null){
786 			return "undef:" ;
787 		}
788 		else if ((ijc.ClassIsNumeric(c))||(ijc.ClassIsChar(c))||(ijc.ClassIsString(c))){
789 			if ((ijs.GetNativeDoubles())&&(ijc.ClassIsDouble(c))){
790 				Double d = (Double)o ;
791 				long l = Double.doubleToLongBits(d.doubleValue()) ;
792 				char ca[] = new char[8] ;
793 				for (int i = 0 ; i < 8 ; i++){
794 					ca[i] = (char)((l >> (8 * i)) & 0xFF) ;
795 				}
796 				return "double:" + Encode(new String(ca)) ;
797 			}
798 			else {
799 				return "scalar:" + Encode(o.toString()) ;
800 			}
801 		}
802 		else if (ijc.ClassIsBool(c)){
803 			String b = o.toString() ;
804 			return "scalar:" + Encode((b.equals("true") ? "1" : "0")) ;
805 		}
806 		else {
807 			if (! (o instanceof org.perl.inline.java.InlineJavaPerlObject)){
808 				// Here we need to register the object in order to send
809 				// it back to the Perl script.
810 				boolean thrown = false ;
811 				String type = "object" ;
812 				if (o instanceof InlineJavaThrown){
813 					thrown = true ;
814 					o = ((InlineJavaThrown)o).GetThrowable() ;
815 					c = o.getClass() ;
816 				}
817 				else if (ijc.ClassIsArray(c)){
818 					type = "array" ;
819 				}
820 				else if (ijc.ClassIsHandle(c)){
821 					type = "handle" ;
822 				}
823 				int id = ijs.PutObject(o) ;
824 
825 				return "java_" + type + ":" + (thrown ? "1" : "0") + ":" + String.valueOf(id) +
826 					":" + c.getName() ;
827 			}
828 			else {
829 				return "perl_object:" + ((InlineJavaPerlObject)o).GetId() +
830 					":" + ((InlineJavaPerlObject)o).GetPkg() ;
831 			}
832 		}
833 	}
834 
835 
DecodeToByteArray(String s)836 	byte[] DecodeToByteArray(String s){
837 		return InlineJavaUtils.DecodeBase64(s.toCharArray()) ;
838 	}
839 
840 
Decode(String s)841 	String Decode(String s) throws InlineJavaException {
842 		try {
843 			if (encoding != null){
844 				return new String(DecodeToByteArray(s), encoding) ;
845 			}
846 			else {
847 				return new String(DecodeToByteArray(s)) ;
848 			}
849 		}
850 		catch (UnsupportedEncodingException e){
851 			throw new InlineJavaException("Unsupported encoding: " + e.getMessage()) ;
852 		}
853 	}
854 
855 
EncodeFromByteArray(byte bytes[])856 	String EncodeFromByteArray(byte bytes[]){
857 		return new String(InlineJavaUtils.EncodeBase64(bytes)) ;
858 	}
859 
860 
Encode(String s)861 	String Encode(String s) throws InlineJavaException {
862 		try {
863 			if (encoding != null){
864 				return EncodeFromByteArray(s.getBytes(encoding)) ;
865 			}
866 			else {
867 				return EncodeFromByteArray(s.getBytes()) ;
868 			}
869 		}
870 		catch (UnsupportedEncodingException e){
871 			throw new InlineJavaException("Unsupported encoding: " + e.getMessage()) ;
872 		}
873 	}
874 
875 
GetResponse()876 	String GetResponse(){
877 		return response ;
878 	}
879 }
880