Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/rmi/rmic/RemoteClass.java
38831 views
1
/*
2
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package sun.rmi.rmic;
27
28
import java.util.Vector;
29
import java.util.Hashtable;
30
import java.util.Enumeration;
31
import java.io.IOException;
32
import java.io.ByteArrayOutputStream;
33
import java.io.DataOutputStream;
34
import java.security.MessageDigest;
35
import java.security.DigestOutputStream;
36
import java.security.NoSuchAlgorithmException;
37
import sun.tools.java.Type;
38
import sun.tools.java.ClassDefinition;
39
import sun.tools.java.ClassDeclaration;
40
import sun.tools.java.MemberDefinition;
41
import sun.tools.java.Identifier;
42
import sun.tools.java.ClassNotFound;
43
44
/**
45
* A RemoteClass object encapsulates RMI-specific information about
46
* a remote implementation class, i.e. a class that implements
47
* one or more remote interfaces.
48
*
49
* WARNING: The contents of this source file are not part of any
50
* supported API. Code that depends on them does so at its own risk:
51
* they are subject to change or removal without notice.
52
*
53
* @author Peter Jones
54
*/
55
public class RemoteClass implements sun.rmi.rmic.RMIConstants {
56
57
/**
58
* Create a RemoteClass object representing the remote meta-information
59
* of the given class.
60
*
61
* Returns true if successful. If the class is not a properly formed
62
* remote implementation class or if some other error occurs, the
63
* return value will be null, and errors will have been reported to
64
* the supplied BatchEnvironment.
65
*/
66
public static RemoteClass forClass(BatchEnvironment env,
67
ClassDefinition implClassDef)
68
{
69
RemoteClass rc = new RemoteClass(env, implClassDef);
70
if (rc.initialize()) {
71
return rc;
72
} else {
73
return null;
74
}
75
}
76
77
/**
78
* Return the ClassDefinition for this class.
79
*/
80
public ClassDefinition getClassDefinition() {
81
return implClassDef;
82
}
83
84
/**
85
* Return the name of the class represented by this object.
86
*/
87
public Identifier getName() {
88
return implClassDef.getName();
89
}
90
91
/**
92
* Return an array of ClassDefinitions representing all of the remote
93
* interfaces implemented by this class.
94
*
95
* A remote interface is any interface that extends Remote,
96
* directly or indirectly. The remote interfaces of a class
97
* are the interfaces directly listed in either the class's
98
* "implements" clause, or the "implements" clause of any
99
* of its superclasses, that are remote interfaces.
100
*
101
* The order of the array returned is arbitrary, and some elements
102
* may be superfluous (i.e., superinterfaces of other interfaces
103
* in the array).
104
*/
105
public ClassDefinition[] getRemoteInterfaces() {
106
return remoteInterfaces.clone();
107
}
108
109
/**
110
* Return an array of RemoteClass.Method objects representing all of
111
* the remote methods implemented by this class, i.e. all of the
112
* methods in the class's remote interfaces.
113
*
114
* The methods in the array are ordered according to the comparision
115
* of the strings consisting of their method name followed by their
116
* type signature, so each method's index in the array corresponds
117
* to its "operation number" in the JDK 1.1 version of the
118
* stub/skeleton protocol.
119
*/
120
public Method[] getRemoteMethods() {
121
return remoteMethods.clone();
122
}
123
124
/**
125
* Return the "interface hash" used to match a stub/skeleton pair for
126
* this class in the JDK 1.1 version of the stub/skeleton protocol.
127
*/
128
public long getInterfaceHash() {
129
return interfaceHash;
130
}
131
132
/**
133
* Return string representation of this object, consisting of
134
* the string "remote class " followed by the class name.
135
*/
136
public String toString() {
137
return "remote class " + implClassDef.getName().toString();
138
}
139
140
/** rmic environment for this object */
141
private BatchEnvironment env;
142
143
/** the remote implementation class this object corresponds to */
144
private ClassDefinition implClassDef;
145
146
/** remote interfaces implemented by this class */
147
private ClassDefinition[] remoteInterfaces;
148
149
/** all the remote methods of this class */
150
private Method[] remoteMethods;
151
152
/** stub/skeleton "interface hash" for this class */
153
private long interfaceHash;
154
155
/** cached definition for certain classes used in this environment */
156
private ClassDefinition defRemote;
157
private ClassDefinition defException;
158
private ClassDefinition defRemoteException;
159
160
/**
161
* Create a RemoteClass instance for the given class. The resulting
162
* object is not yet initialized.
163
*/
164
private RemoteClass(BatchEnvironment env, ClassDefinition implClassDef) {
165
this.env = env;
166
this.implClassDef = implClassDef;
167
}
168
169
/**
170
* Validate that the remote implementation class is properly formed
171
* and fill in the data structures required by the public interface.
172
*/
173
private boolean initialize() {
174
/*
175
* Verify that the "impl" is really a class, not an interface.
176
*/
177
if (implClassDef.isInterface()) {
178
env.error(0, "rmic.cant.make.stubs.for.interface",
179
implClassDef.getName());
180
return false;
181
}
182
183
/*
184
* Initialize cached definitions for the Remote interface and
185
* the RemoteException class.
186
*/
187
try {
188
defRemote =
189
env.getClassDeclaration(idRemote).getClassDefinition(env);
190
defException =
191
env.getClassDeclaration(idJavaLangException).
192
getClassDefinition(env);
193
defRemoteException =
194
env.getClassDeclaration(idRemoteException).
195
getClassDefinition(env);
196
} catch (ClassNotFound e) {
197
env.error(0, "rmic.class.not.found", e.name);
198
return false;
199
}
200
201
/*
202
* Here we find all of the remote interfaces of our remote
203
* implementation class. For each class up the superclass
204
* chain, add each directly-implemented interface that
205
* somehow extends Remote to a list.
206
*/
207
Vector<ClassDefinition> remotesImplemented = // list of remote interfaces found
208
new Vector<ClassDefinition>();
209
for (ClassDefinition classDef = implClassDef;
210
classDef != null;)
211
{
212
try {
213
ClassDeclaration[] interfaces = classDef.getInterfaces();
214
for (int i = 0; i < interfaces.length; i++) {
215
ClassDefinition interfaceDef =
216
interfaces[i].getClassDefinition(env);
217
/*
218
* Add interface to the list if it extends Remote and
219
* it is not already there.
220
*/
221
if (!remotesImplemented.contains(interfaceDef) &&
222
defRemote.implementedBy(env, interfaces[i]))
223
{
224
remotesImplemented.addElement(interfaceDef);
225
/***** <DEBUG> */
226
if (env.verbose()) {
227
System.out.println("[found remote interface: " +
228
interfaceDef.getName() + "]");
229
/***** </DEBUG> */
230
}
231
}
232
}
233
234
/*
235
* Verify that the candidate remote implementation class
236
* implements at least one remote interface directly.
237
*/
238
if (classDef == implClassDef && remotesImplemented.isEmpty()) {
239
if (defRemote.implementedBy(env,
240
implClassDef.getClassDeclaration()))
241
{
242
/*
243
* This error message is used if the class does
244
* implement a remote interface through one of
245
* its superclasses, but not directly.
246
*/
247
env.error(0, "rmic.must.implement.remote.directly",
248
implClassDef.getName());
249
} else {
250
/*
251
* This error message is used if the class never
252
* implements a remote interface.
253
*/
254
env.error(0, "rmic.must.implement.remote",
255
implClassDef.getName());
256
}
257
return false;
258
}
259
260
/*
261
* Get definition for next superclass.
262
*/
263
classDef = (classDef.getSuperClass() != null ?
264
classDef.getSuperClass().getClassDefinition(env) :
265
null);
266
267
} catch (ClassNotFound e) {
268
env.error(0, "class.not.found", e.name, classDef.getName());
269
return false;
270
}
271
}
272
273
/*
274
* The "remotesImplemented" vector now contains all of the remote
275
* interfaces directly implemented by the remote class or by any
276
* of its superclasses.
277
*
278
* At this point, we could optimize the list by removing superfluous
279
* entries, i.e. any interfaces that are implemented by some other
280
* interface in the list anyway.
281
*
282
* This should be correct; would it be worthwhile?
283
*
284
* for (int i = 0; i < remotesImplemented.size();) {
285
* ClassDefinition interfaceDef =
286
* (ClassDefinition) remotesImplemented.elementAt(i);
287
* boolean isOtherwiseImplemented = false;
288
* for (int j = 0; j < remotesImplemented.size; j++) {
289
* if (j != i &&
290
* interfaceDef.implementedBy(env, (ClassDefinition)
291
* remotesImplemented.elementAt(j).
292
* getClassDeclaration()))
293
* {
294
* isOtherwiseImplemented = true;
295
* break;
296
* }
297
* }
298
* if (isOtherwiseImplemented) {
299
* remotesImplemented.removeElementAt(i);
300
* } else {
301
* ++i;
302
* }
303
* }
304
*/
305
306
/*
307
* Now we collect the methods from all of the remote interfaces
308
* into a hashtable.
309
*/
310
Hashtable<String, Method> methods = new Hashtable<String, Method>();
311
boolean errors = false;
312
for (Enumeration<ClassDefinition> enumeration
313
= remotesImplemented.elements();
314
enumeration.hasMoreElements();)
315
{
316
ClassDefinition interfaceDef = enumeration.nextElement();
317
if (!collectRemoteMethods(interfaceDef, methods))
318
errors = true;
319
}
320
if (errors)
321
return false;
322
323
/*
324
* Convert vector of remote interfaces to an array
325
* (order is not important for this array).
326
*/
327
remoteInterfaces = new ClassDefinition[remotesImplemented.size()];
328
remotesImplemented.copyInto(remoteInterfaces);
329
330
/*
331
* Sort table of remote methods into an array. The elements are
332
* sorted in ascending order of the string of the method's name
333
* and type signature, so that each elements index is equal to
334
* its operation number of the JDK 1.1 version of the stub/skeleton
335
* protocol.
336
*/
337
String[] orderedKeys = new String[methods.size()];
338
int count = 0;
339
for (Enumeration<Method> enumeration = methods.elements();
340
enumeration.hasMoreElements();)
341
{
342
Method m = enumeration.nextElement();
343
String key = m.getNameAndDescriptor();
344
int i;
345
for (i = count; i > 0; --i) {
346
if (key.compareTo(orderedKeys[i - 1]) >= 0) {
347
break;
348
}
349
orderedKeys[i] = orderedKeys[i - 1];
350
}
351
orderedKeys[i] = key;
352
++count;
353
}
354
remoteMethods = new Method[methods.size()];
355
for (int i = 0; i < remoteMethods.length; i++) {
356
remoteMethods[i] = methods.get(orderedKeys[i]);
357
/***** <DEBUG> */
358
if (env.verbose()) {
359
System.out.print("[found remote method <" + i + ">: " +
360
remoteMethods[i].getOperationString());
361
ClassDeclaration[] exceptions =
362
remoteMethods[i].getExceptions();
363
if (exceptions.length > 0)
364
System.out.print(" throws ");
365
for (int j = 0; j < exceptions.length; j++) {
366
if (j > 0)
367
System.out.print(", ");
368
System.out.print(exceptions[j].getName());
369
}
370
System.out.println("]");
371
}
372
/***** </DEBUG> */
373
}
374
375
/**
376
* Finally, pre-compute the interface hash to be used by
377
* stubs/skeletons for this remote class.
378
*/
379
interfaceHash = computeInterfaceHash();
380
381
return true;
382
}
383
384
/**
385
* Collect and validate all methods from given interface and all of
386
* its superinterfaces as remote methods. Remote methods are added
387
* to the supplied hashtable. Returns true if successful,
388
* or false if an error occurred.
389
*/
390
private boolean collectRemoteMethods(ClassDefinition interfaceDef,
391
Hashtable<String, Method> table)
392
{
393
if (!interfaceDef.isInterface()) {
394
throw new Error(
395
"expected interface, not class: " + interfaceDef.getName());
396
}
397
398
/*
399
* rmic used to enforce that a remote interface could not extend
400
* a non-remote interface, i.e. an interface that did not itself
401
* extend from Remote. The current version of rmic does not have
402
* this restriction, so the following code is now commented out.
403
*
404
* Verify that this interface extends Remote, since all interfaces
405
* extended by a remote interface must implement Remote.
406
*
407
* try {
408
* if (!defRemote.implementedBy(env,
409
* interfaceDef.getClassDeclaration()))
410
* {
411
* env.error(0, "rmic.can.mix.remote.nonremote",
412
* interfaceDef.getName());
413
* return false;
414
* }
415
* } catch (ClassNotFound e) {
416
* env.error(0, "class.not.found", e.name,
417
* interfaceDef.getName());
418
* return false;
419
* }
420
*/
421
422
boolean errors = false;
423
424
/*
425
* Search interface's members for methods.
426
*/
427
nextMember:
428
for (MemberDefinition member = interfaceDef.getFirstMember();
429
member != null;
430
member = member.getNextMember())
431
{
432
if (member.isMethod() &&
433
!member.isConstructor() && !member.isInitializer())
434
{
435
/*
436
* Verify that each method throws RemoteException.
437
*/
438
ClassDeclaration[] exceptions = member.getExceptions(env);
439
boolean hasRemoteException = false;
440
for (int i = 0; i < exceptions.length; i++) {
441
/*
442
* rmic used to enforce that a remote method had to
443
* explicitly list RemoteException in its "throws"
444
* clause; i.e., just throwing Exception was not
445
* acceptable. The current version of rmic does not
446
* have this restriction, so the following code is
447
* now commented out. Instead, the method is
448
* considered valid if RemoteException is a subclass
449
* of any of the methods declared exceptions.
450
*
451
* if (exceptions[i].getName().equals(
452
* idRemoteException))
453
* {
454
* hasRemoteException = true;
455
* break;
456
* }
457
*/
458
try {
459
if (defRemoteException.subClassOf(
460
env, exceptions[i]))
461
{
462
hasRemoteException = true;
463
break;
464
}
465
} catch (ClassNotFound e) {
466
env.error(0, "class.not.found", e.name,
467
interfaceDef.getName());
468
continue nextMember;
469
}
470
}
471
/*
472
* If this method did not throw RemoteException as required,
473
* generate the error but continue, so that multiple such
474
* errors can be reported.
475
*/
476
if (!hasRemoteException) {
477
env.error(0, "rmic.must.throw.remoteexception",
478
interfaceDef.getName(), member.toString());
479
errors = true;
480
continue nextMember;
481
}
482
483
/*
484
* Verify that the implementation of this method throws only
485
* java.lang.Exception or its subclasses (fix bugid 4092486).
486
* JRMP does not support remote methods throwing
487
* java.lang.Throwable or other subclasses.
488
*/
489
try {
490
MemberDefinition implMethod = implClassDef.findMethod(
491
env, member.getName(), member.getType());
492
if (implMethod != null) { // should not be null
493
exceptions = implMethod.getExceptions(env);
494
for (int i = 0; i < exceptions.length; i++) {
495
if (!defException.superClassOf(
496
env, exceptions[i]))
497
{
498
env.error(0, "rmic.must.only.throw.exception",
499
implMethod.toString(),
500
exceptions[i].getName());
501
errors = true;
502
continue nextMember;
503
}
504
}
505
}
506
} catch (ClassNotFound e) {
507
env.error(0, "class.not.found", e.name,
508
implClassDef.getName());
509
continue nextMember;
510
}
511
512
/*
513
* Create RemoteClass.Method object to represent this method
514
* found in a remote interface.
515
*/
516
Method newMethod = new Method(member);
517
/*
518
* Store remote method's representation in the table of
519
* remote methods found, keyed by its name and parameter
520
* signature.
521
*
522
* If the table already contains an entry with the same
523
* method name and parameter signature, then we must
524
* replace the old entry with a Method object that
525
* represents a legal combination of the old and the new
526
* methods; specifically, the combined method must have
527
* a throws list that contains (only) all of the checked
528
* exceptions that can be thrown by both the old or
529
* the new method (see bugid 4070653).
530
*/
531
String key = newMethod.getNameAndDescriptor();
532
Method oldMethod = table.get(key);
533
if (oldMethod != null) {
534
newMethod = newMethod.mergeWith(oldMethod);
535
if (newMethod == null) {
536
errors = true;
537
continue nextMember;
538
}
539
}
540
table.put(key, newMethod);
541
}
542
}
543
544
/*
545
* Recursively collect methods for all superinterfaces.
546
*/
547
try {
548
ClassDeclaration[] superDefs = interfaceDef.getInterfaces();
549
for (int i = 0; i < superDefs.length; i++) {
550
ClassDefinition superDef =
551
superDefs[i].getClassDefinition(env);
552
if (!collectRemoteMethods(superDef, table))
553
errors = true;
554
}
555
} catch (ClassNotFound e) {
556
env.error(0, "class.not.found", e.name, interfaceDef.getName());
557
return false;
558
}
559
560
return !errors;
561
}
562
563
/**
564
* Compute the "interface hash" of the stub/skeleton pair for this
565
* remote implementation class. This is the 64-bit value used to
566
* enforce compatibility between a stub and a skeleton using the
567
* JDK 1.1 version of the stub/skeleton protocol.
568
*
569
* It is calculated using the first 64 bits of a SHA digest. The
570
* digest is from a stream consisting of the following data:
571
* (int) stub version number, always 1
572
* for each remote method, in order of operation number:
573
* (UTF) method name
574
* (UTF) method type signature
575
* for each declared exception, in alphabetical name order:
576
* (UTF) name of exception class
577
*
578
*/
579
private long computeInterfaceHash() {
580
long hash = 0;
581
ByteArrayOutputStream sink = new ByteArrayOutputStream(512);
582
try {
583
MessageDigest md = MessageDigest.getInstance("SHA");
584
DataOutputStream out = new DataOutputStream(
585
new DigestOutputStream(sink, md));
586
587
out.writeInt(INTERFACE_HASH_STUB_VERSION);
588
for (int i = 0; i < remoteMethods.length; i++) {
589
MemberDefinition m = remoteMethods[i].getMemberDefinition();
590
Identifier name = m.getName();
591
Type type = m.getType();
592
593
out.writeUTF(name.toString());
594
// type signatures already use mangled class names
595
out.writeUTF(type.getTypeSignature());
596
597
ClassDeclaration exceptions[] = m.getExceptions(env);
598
sortClassDeclarations(exceptions);
599
for (int j = 0; j < exceptions.length; j++) {
600
out.writeUTF(Names.mangleClass(
601
exceptions[j].getName()).toString());
602
}
603
}
604
out.flush();
605
606
// use only the first 64 bits of the digest for the hash
607
byte hashArray[] = md.digest();
608
for (int i = 0; i < Math.min(8, hashArray.length); i++) {
609
hash += ((long) (hashArray[i] & 0xFF)) << (i * 8);
610
}
611
} catch (IOException e) {
612
throw new Error(
613
"unexpected exception computing intetrface hash: " + e);
614
} catch (NoSuchAlgorithmException e) {
615
throw new Error(
616
"unexpected exception computing intetrface hash: " + e);
617
}
618
619
return hash;
620
}
621
622
/**
623
* Sort array of class declarations alphabetically by their mangled
624
* fully-qualified class name. This is used to feed a method's exceptions
625
* in a canonical order into the digest stream for the interface hash
626
* computation.
627
*/
628
private void sortClassDeclarations(ClassDeclaration[] decl) {
629
for (int i = 1; i < decl.length; i++) {
630
ClassDeclaration curr = decl[i];
631
String name = Names.mangleClass(curr.getName()).toString();
632
int j;
633
for (j = i; j > 0; j--) {
634
if (name.compareTo(
635
Names.mangleClass(decl[j - 1].getName()).toString()) >= 0)
636
{
637
break;
638
}
639
decl[j] = decl[j - 1];
640
}
641
decl[j] = curr;
642
}
643
}
644
645
646
/**
647
* A RemoteClass.Method object encapsulates RMI-specific information
648
* about a particular remote method in the remote implementation class
649
* represented by the outer instance.
650
*/
651
public class Method implements Cloneable {
652
653
/**
654
* Return the definition of the actual class member corresponing
655
* to this method of a remote interface.
656
*
657
* REMIND: Can this method be removed?
658
*/
659
public MemberDefinition getMemberDefinition() {
660
return memberDef;
661
}
662
663
/**
664
* Return the name of this method.
665
*/
666
public Identifier getName() {
667
return memberDef.getName();
668
}
669
670
/**
671
* Return the type of this method.
672
*/
673
public Type getType() {
674
return memberDef.getType();
675
}
676
677
/**
678
* Return an array of the exception classes declared to be
679
* thrown by this remote method.
680
*
681
* For methods with the same name and type signature inherited
682
* from multiple remote interfaces, the array will contain
683
* the set of exceptions declared in all of the interfaces'
684
* methods that can be legally thrown in each of them.
685
*/
686
public ClassDeclaration[] getExceptions() {
687
return exceptions.clone();
688
}
689
690
/**
691
* Return the "method hash" used to identify this remote method
692
* in the JDK 1.2 version of the stub protocol.
693
*/
694
public long getMethodHash() {
695
return methodHash;
696
}
697
698
/**
699
* Return the string representation of this method.
700
*/
701
public String toString() {
702
return memberDef.toString();
703
}
704
705
/**
706
* Return the string representation of this method appropriate
707
* for the construction of a java.rmi.server.Operation object.
708
*/
709
public String getOperationString() {
710
return memberDef.toString();
711
}
712
713
/**
714
* Return a string consisting of this method's name followed by
715
* its method descriptor, using the Java VM's notation for
716
* method descriptors (see section 4.3.3 of The Java Virtual
717
* Machine Specification).
718
*/
719
public String getNameAndDescriptor() {
720
return memberDef.getName().toString() +
721
memberDef.getType().getTypeSignature();
722
}
723
724
/**
725
* Member definition for this method, from one of the remote
726
* interfaces that this method was found in.
727
*
728
* Note that this member definition may be only one of several
729
* member defintions that correspond to this remote method object,
730
* if several of this class's remote interfaces contain methods
731
* with the same name and type signature. Therefore, this member
732
* definition may declare more exceptions thrown that this remote
733
* method does.
734
*/
735
private MemberDefinition memberDef;
736
737
/** stub "method hash" to identify this method */
738
private long methodHash;
739
740
/**
741
* Exceptions declared to be thrown by this remote method.
742
*
743
* This list can include superfluous entries, such as
744
* unchecked exceptions and subclasses of other entries.
745
*/
746
private ClassDeclaration[] exceptions;
747
748
/**
749
* Create a new Method object corresponding to the given
750
* method definition.
751
*/
752
/*
753
* Temporarily comment out the private modifier until
754
* the VM allows outer class to access inner class's
755
* private constructor
756
*/
757
/* private */ Method(MemberDefinition memberDef) {
758
this.memberDef = memberDef;
759
exceptions = memberDef.getExceptions(env);
760
methodHash = computeMethodHash();
761
}
762
763
/**
764
* Cloning is supported by returning a shallow copy of this object.
765
*/
766
protected Object clone() {
767
try {
768
return super.clone();
769
} catch (CloneNotSupportedException e) {
770
throw new Error("clone failed");
771
}
772
}
773
774
/**
775
* Return a new Method object that is a legal combination of
776
* this method object and another one.
777
*
778
* This requires determining the exceptions declared by the
779
* combined method, which must be (only) all of the exceptions
780
* declared in both old Methods that may thrown in either of
781
* them.
782
*/
783
private Method mergeWith(Method other) {
784
if (!getName().equals(other.getName()) ||
785
!getType().equals(other.getType()))
786
{
787
throw new Error("attempt to merge method \"" +
788
other.getNameAndDescriptor() + "\" with \"" +
789
getNameAndDescriptor());
790
}
791
792
Vector<ClassDeclaration> legalExceptions
793
= new Vector<ClassDeclaration>();
794
try {
795
collectCompatibleExceptions(
796
other.exceptions, exceptions, legalExceptions);
797
collectCompatibleExceptions(
798
exceptions, other.exceptions, legalExceptions);
799
} catch (ClassNotFound e) {
800
env.error(0, "class.not.found", e.name,
801
getClassDefinition().getName());
802
return null;
803
}
804
805
Method merged = (Method) clone();
806
merged.exceptions = new ClassDeclaration[legalExceptions.size()];
807
legalExceptions.copyInto(merged.exceptions);
808
809
return merged;
810
}
811
812
/**
813
* Add to the supplied list all exceptions in the "from" array
814
* that are subclasses of an exception in the "with" array.
815
*/
816
private void collectCompatibleExceptions(ClassDeclaration[] from,
817
ClassDeclaration[] with,
818
Vector<ClassDeclaration> list)
819
throws ClassNotFound
820
{
821
for (int i = 0; i < from.length; i++) {
822
ClassDefinition exceptionDef = from[i].getClassDefinition(env);
823
if (!list.contains(from[i])) {
824
for (int j = 0; j < with.length; j++) {
825
if (exceptionDef.subClassOf(env, with[j])) {
826
list.addElement(from[i]);
827
break;
828
}
829
}
830
}
831
}
832
}
833
834
/**
835
* Compute the "method hash" of this remote method. The method
836
* hash is a long containing the first 64 bits of the SHA digest
837
* from the UTF encoded string of the method name and descriptor.
838
*
839
* REMIND: Should this method share implementation code with
840
* the outer class's computeInterfaceHash() method?
841
*/
842
private long computeMethodHash() {
843
long hash = 0;
844
ByteArrayOutputStream sink = new ByteArrayOutputStream(512);
845
try {
846
MessageDigest md = MessageDigest.getInstance("SHA");
847
DataOutputStream out = new DataOutputStream(
848
new DigestOutputStream(sink, md));
849
850
String methodString = getNameAndDescriptor();
851
/***** <DEBUG> */
852
if (env.verbose()) {
853
System.out.println("[string used for method hash: \"" +
854
methodString + "\"]");
855
}
856
/***** </DEBUG> */
857
out.writeUTF(methodString);
858
859
// use only the first 64 bits of the digest for the hash
860
out.flush();
861
byte hashArray[] = md.digest();
862
for (int i = 0; i < Math.min(8, hashArray.length); i++) {
863
hash += ((long) (hashArray[i] & 0xFF)) << (i * 8);
864
}
865
} catch (IOException e) {
866
throw new Error(
867
"unexpected exception computing intetrface hash: " + e);
868
} catch (NoSuchAlgorithmException e) {
869
throw new Error(
870
"unexpected exception computing intetrface hash: " + e);
871
}
872
873
return hash;
874
}
875
}
876
}
877
878