Browse Source

Merge pull request #8951 in CORE/base-third from final/10.0 to persist/10.0

* commit '0748323aeacdba343bf862cb8c7bb5cb486942aa':
  REPORT-95610 hsqldb 升级回退
  REPORT-95610 hsqldb存在公开漏洞需要升级nostat
  REPORT-95576 spring framework 高危漏洞,需要删除类
  REPORT-94814 备份还原报错npe
  REPORT-93688 REPORT-94439 创建hsql连接超时
  REPORT-93688 REPORT-94439 创建hsql连接超时
persist/10.0
superman 1 year ago
parent
commit
b730cdac0a
  1. 2
      fine-hibernate/src/main/java/com/fr/third/org/hibernate/engine/internal/StatefulPersistenceContext.java
  2. 14
      fine-hsqldb/src/main/java/com/fr/third/org/hsqldb/cmdline/sqltool/SqlTool.syntax_de.text
  3. 30
      fine-hsqldb/src/main/java/com/fr/third/org/hsqldb/cmdline/sqltool/special.help_de.text
  4. 8
      fine-hsqldb/src/main/java/com/fr/third/org/hsqldb/cmdline/sqltool_de.properties
  5. 71
      fine-hsqldb/src/main/java/com/fr/third/org/hsqldb/lib/FrameworkLogger.java
  6. 46
      fine-hsqldb/src/main/java/com/fr/third/org/hsqldb/resources/sql-state-messages_es.properties
  7. 1
      fine-spring/readme.md
  8. 4
      fine-spring/src/main/java/com/fr/third/springframework/ejb/access/AbstractRemoteSlsbInvokerInterceptor.java
  9. 40
      fine-spring/src/main/java/com/fr/third/springframework/ejb/access/SimpleRemoteSlsbInvokerInterceptor.java
  10. 194
      fine-spring/src/main/java/com/fr/third/springframework/remoting/caucho/BurlapClientInterceptor.java
  11. 97
      fine-spring/src/main/java/com/fr/third/springframework/remoting/caucho/BurlapExporter.java
  12. 73
      fine-spring/src/main/java/com/fr/third/springframework/remoting/caucho/BurlapProxyFactoryBean.java
  13. 76
      fine-spring/src/main/java/com/fr/third/springframework/remoting/caucho/BurlapServiceExporter.java
  14. 297
      fine-spring/src/main/java/com/fr/third/springframework/remoting/caucho/HessianClientInterceptor.java
  15. 247
      fine-spring/src/main/java/com/fr/third/springframework/remoting/caucho/HessianExporter.java
  16. 70
      fine-spring/src/main/java/com/fr/third/springframework/remoting/caucho/HessianProxyFactoryBean.java
  17. 73
      fine-spring/src/main/java/com/fr/third/springframework/remoting/caucho/HessianServiceExporter.java
  18. 79
      fine-spring/src/main/java/com/fr/third/springframework/remoting/caucho/SimpleBurlapServiceExporter.java
  19. 77
      fine-spring/src/main/java/com/fr/third/springframework/remoting/caucho/SimpleHessianServiceExporter.java
  20. 10
      fine-spring/src/main/java/com/fr/third/springframework/remoting/caucho/package-info.java
  21. 299
      fine-spring/src/main/java/com/fr/third/springframework/remoting/httpinvoker/AbstractHttpInvokerRequestExecutor.java
  22. 418
      fine-spring/src/main/java/com/fr/third/springframework/remoting/httpinvoker/HttpComponentsHttpInvokerRequestExecutor.java
  23. 42
      fine-spring/src/main/java/com/fr/third/springframework/remoting/httpinvoker/HttpInvokerClientConfiguration.java
  24. 233
      fine-spring/src/main/java/com/fr/third/springframework/remoting/httpinvoker/HttpInvokerClientInterceptor.java
  25. 86
      fine-spring/src/main/java/com/fr/third/springframework/remoting/httpinvoker/HttpInvokerProxyFactoryBean.java
  26. 59
      fine-spring/src/main/java/com/fr/third/springframework/remoting/httpinvoker/HttpInvokerRequestExecutor.java
  27. 225
      fine-spring/src/main/java/com/fr/third/springframework/remoting/httpinvoker/HttpInvokerServiceExporter.java
  28. 232
      fine-spring/src/main/java/com/fr/third/springframework/remoting/httpinvoker/SimpleHttpInvokerRequestExecutor.java
  29. 184
      fine-spring/src/main/java/com/fr/third/springframework/remoting/httpinvoker/SimpleHttpInvokerServiceExporter.java
  30. 11
      fine-spring/src/main/java/com/fr/third/springframework/remoting/httpinvoker/package-info.java
  31. 119
      fine-spring/src/main/java/com/fr/third/springframework/remoting/rmi/CodebaseAwareObjectInputStream.java
  32. 510
      fine-spring/src/main/java/com/fr/third/springframework/remoting/rmi/JndiRmiClientInterceptor.java
  33. 102
      fine-spring/src/main/java/com/fr/third/springframework/remoting/rmi/JndiRmiProxyFactoryBean.java
  34. 149
      fine-spring/src/main/java/com/fr/third/springframework/remoting/rmi/JndiRmiServiceExporter.java
  35. 181
      fine-spring/src/main/java/com/fr/third/springframework/remoting/rmi/RemoteInvocationSerializingExporter.java
  36. 76
      fine-spring/src/main/java/com/fr/third/springframework/remoting/rmi/RmiBasedExporter.java
  37. 416
      fine-spring/src/main/java/com/fr/third/springframework/remoting/rmi/RmiClientInterceptor.java
  38. 193
      fine-spring/src/main/java/com/fr/third/springframework/remoting/rmi/RmiClientInterceptorUtils.java
  39. 59
      fine-spring/src/main/java/com/fr/third/springframework/remoting/rmi/RmiInvocationHandler.java
  40. 77
      fine-spring/src/main/java/com/fr/third/springframework/remoting/rmi/RmiInvocationWrapper.java
  41. 91
      fine-spring/src/main/java/com/fr/third/springframework/remoting/rmi/RmiProxyFactoryBean.java
  42. 314
      fine-spring/src/main/java/com/fr/third/springframework/remoting/rmi/RmiRegistryFactoryBean.java
  43. 462
      fine-spring/src/main/java/com/fr/third/springframework/remoting/rmi/RmiServiceExporter.java
  44. 6
      fine-spring/src/main/java/com/fr/third/springframework/remoting/rmi/package-info.java

2
fine-hibernate/src/main/java/com/fr/third/org/hibernate/engine/internal/StatefulPersistenceContext.java

@ -223,7 +223,7 @@ public class StatefulPersistenceContext implements PersistenceContext {
for ( Entry<Object, EntityEntry> objectEntityEntryEntry : entityEntryContext.reentrantSafeEntityEntries() ) { for ( Entry<Object, EntityEntry> objectEntityEntryEntry : entityEntryContext.reentrantSafeEntityEntries() ) {
// todo : I dont think this need be reentrant safe // todo : I dont think this need be reentrant safe
if ( objectEntityEntryEntry.getKey() instanceof PersistentAttributeInterceptable ) { if ( objectEntityEntryEntry != null && objectEntityEntryEntry.getKey() instanceof PersistentAttributeInterceptable ) {
final PersistentAttributeInterceptor interceptor = ( (PersistentAttributeInterceptable) objectEntityEntryEntry.getKey() ).$$_hibernate_getInterceptor(); final PersistentAttributeInterceptor interceptor = ( (PersistentAttributeInterceptable) objectEntityEntryEntry.getKey() ).$$_hibernate_getInterceptor();
if ( interceptor instanceof LazyAttributeLoadingInterceptor ) { if ( interceptor instanceof LazyAttributeLoadingInterceptor ) {
( (LazyAttributeLoadingInterceptor) interceptor ).unsetSession(); ( (LazyAttributeLoadingInterceptor) interceptor ).unsetSession();

14
fine-hsqldb/src/main/java/com/fr/third/org/hsqldb/cmdline/sqltool/SqlTool.syntax_de.text

@ -5,16 +5,16 @@ Optionen:
--noInput Nicht von stdin lesen (Standardeinstellung wenn --noInput Nicht von stdin lesen (Standardeinstellung wenn
SQL-Datei angegeben oder der Schalter --sql SQL-Datei angegeben oder der Schalter --sql
benutzt wird). benutzt wird).
--stdInput Liest von stdin ZUSÄTZLICH zu SQL-Dateien/--sql --stdInput Liest von stdin ZUS<EFBFBD>TZLICH zu SQL-Dateien/--sql
Eingabe. Eingabe.
--inlineRc=url=val1,user=val2[,x=val3...][,password=] Inline RC-Variablen --inlineRc=url=val1,user=val2[,x=val3...][,password=] Inline RC-Variablen
--debug Gibt Debug Infos auf stderr aus. --debug Gibt Debug Infos auf stderr aus.
--noAutoFile Führt die Datei auto.sql im Home-Verzeichniss --noAutoFile F<EFBFBD>hrt die Datei auto.sql im Home-Verzeichniss
nicht aus. nicht aus.
--autoCommit Auto-commit JDBC DML Befehle --autoCommit Auto-commit JDBC DML Befehle
--sql="SQL; Anweisungen;" Führt die angegebene SQL-Anweisung aus statt von --sql="SQL; Anweisungen;" F<EFBFBD>hrt die angegebene SQL-Anweisung aus statt von
stdin zu lesen (bevor SQL-Dateien stdin zu lesen (bevor SQL-Dateien
- wenn angegeben - ausgeführt werden) - wenn angegeben - ausgef<EFBFBD>hrt werden)
wobei 'SQL' aus SQL-Befehlen gebildet wird. Siehe wobei 'SQL' aus SQL-Befehlen gebildet wird. Siehe
Handbuch. Handbuch.
--rcFile=path/file.rc Verwende Info-Datei [$HOME/sqltool.rc] --rcFile=path/file.rc Verwende Info-Datei [$HOME/sqltool.rc]
@ -22,7 +22,7 @@ Optionen:
--setVar=NAME1=val1[,NAME2=val2...] PL Variablen --setVar=NAME1=val1[,NAME2=val2...] PL Variablen
--driver=a.b.c.Driver JDBC Treiber Class [%{2}] --driver=a.b.c.Driver JDBC Treiber Class [%{2}]
urlid ID von Url/Benutzername/Passwort in der RC-Datei urlid ID von Url/Benutzername/Passwort in der RC-Datei
datei1.sql... SQL Dateien auszuführen [stdin] datei1.sql... SQL Dateien auszuf<EFBFBD>hren [stdin]
(Benutzen Sie '-' für Nicht-Interaktives stdin!). (Benutzen Sie '-' f<EFBFBD>r Nicht-Interaktives stdin!).
Lesen Sie das SqlTool Handbuch für unterstützte sqltool.* Systemeigenschaften. Lesen Sie das SqlTool Handbuch f<EFBFBD>r unterst<EFBFBD>tzte sqltool.* Systemeigenschaften.
SqlTool v. %{1}. SqlTool v. %{1}.

30
fine-hsqldb/src/main/java/com/fr/third/org/hsqldb/cmdline/sqltool/special.help_de.text

@ -1,32 +1,32 @@
Sonderbefehle. Sonderbefehle.
Bei Filterzeichenketten wird die Groß/Kleinschreibung beachtet. Bei Filterzeichenketten wird die Gro<EFBFBD>/Kleinschreibung beachtet.
Verwenden Sie "SCHEMANAME.", um auf ein Schema zu begrenzen. Verwenden Sie "SCHEMANAME.", um auf ein Schema zu begrenzen.
\? Sonderbefehle Hilfe \? Sonderbefehle Hilfe
\. Geben Sie reines SQL ein (Raw-SQL). Schließen Sie \. Geben Sie reines SQL ein (Raw-SQL). Schlie<EFBFBD>en Sie
mit einer Leerzeile ab, die nur einen "." enthält mit einer Leerzeile ab, die nur einen "." enth<EFBFBD>lt
\= Commitet JDBC Transaktionen. \= Commitet JDBC Transaktionen.
\! BEFEHL [ARGE] Führt externe Programme aus (stdin wird nicht \! BEFEHL [ARGE] F<EFBFBD>hrt externe Programme aus (stdin wird nicht
unterstützt). unterst<EFBFBD>tzt).
\a [true|false] Commitet automatisch JDBC DML Befehle. \a [true|false] Commitet automatisch JDBC DML Befehle.
\b Speichert die nächste Ergebnismenge im Binärpuffer \b Speichert die n<EFBFBD>chste Ergebnismenge im Bin<EFBFBD>rpuffer
(keine Ausgabe). (keine Ausgabe).
\bd pfad/datei.bin Speichert den Binärpuffer in Datei. \bd pfad/datei.bin Speichert den Bin<EFBFBD>rpuffer in Datei.
\bl pfad/datei.bin Lädt Datei in den Binärpuffer \bl pfad/datei.bin L<EFBFBD>dt Datei in den Bin<EFBFBD>rpuffer
\bp Verwenden Sie ? in der nächsten SQL-Anweisung um \bp Verwenden Sie ? in der n<EFBFBD>chsten SQL-Anweisung um
den Binärpuffer hochzuladen. den Bin<EFBFBD>rpuffer hochzuladen.
\c [true|false] Weiter nach Fehler oder Abbruch nach Fehler. \c [true|false] Weiter nach Fehler oder Abbruch nach Fehler.
\d OBJEKTNAME [regx] Beschreibt Spalten von Tabellen oder Views \d OBJEKTNAME [regx] Beschreibt Spalten von Tabellen oder Views
\d{tvsiSanur*?} [Zeichenkette] Listet Objekte der spezifizierten Art: \d{tvsiSanur*?} [Zeichenkette] Listet Objekte der spezifizierten Art:
(Tbln/Views/Seqs/Indexe/SysTbln/Aliase/SchemaNamen/Benutzer/Rollenn/tbl-ähnlich) (Tbln/Views/Seqs/Indexe/SysTbln/Aliase/SchemaNamen/Benutzer/Rollenn/tbl-<EFBFBD>hnlich)
\h [true|false] Schaltet in den HTML-Ausgabe-Modus. \h [true|false] Schaltet in den HTML-Ausgabe-Modus.
\i pfad/datei.sql Befehle aus externer Datei ausführen/einbinden \i pfad/datei.sql Befehle aus externer Datei ausf<EFBFBD>hren/einbinden
\j [urlid] Anzeige JDBC-Verbindung Details, oder zu 'urlid' zu \j [urlid] Anzeige JDBC-Verbindung Details, oder zu 'urlid' zu
verbinden verbinden
\j acct pwd jdbc:url Herstellung der Verbindung zum JDBC-Datenquelle auf \j acct pwd jdbc:url Herstellung der Verbindung zum JDBC-Datenquelle auf
URL URL
\l LEVEL Log-Meld. Log-Meldung. (verfügbare Levels mit '\l?' anzeigen \l LEVEL Log-Meld. Log-Meldung. (verf<EFBFBD>gbare Levels mit '\l?' anzeigen
lassen.) lassen.)
\m pfad/datei.dsv [*] Importiert Datensätze aus einer DSV-Textdatei in \m pfad/datei.dsv [*] Importiert Datens<EFBFBD>tze aus einer DSV-Textdatei in
eine Tabelle. (weitere Optionen '\m?'). eine Tabelle. (weitere Optionen '\m?').
\mq pfad/datei.csv Ditto, aber mit traditionellen CSV doppelt zitiert. \mq pfad/datei.csv Ditto, aber mit traditionellen CSV doppelt zitiert.
\o [datei/pfad.html] Leitet (oder stoppt dies) die Ausgabe der Abfrage in \o [datei/pfad.html] Leitet (oder stoppt dies) die Ausgabe der Abfrage in
@ -34,7 +34,7 @@ Verwenden Sie "SCHEMANAME.", um auf ein Schema zu begrenzen.
\p [Eine Nachricht] Gibt Nachricht auf stdout aus \p [Eine Nachricht] Gibt Nachricht auf stdout aus
\q [Abbruchmeldung] Beendet das Programm (oder beenden Sie es mit \q [Abbruchmeldung] Beendet das Programm (oder beenden Sie es mit
STRG-Z oder STRG-D). STRG-Z oder STRG-D).
\t [true|false] Gibt die Ausführungszeiten für alle SQL-Befehle aus. \t [true|false] Gibt die Ausf<EFBFBD>hrungszeiten f<EFBFBD>r alle SQL-Befehle aus.
\v [TRAN_ISO_LEVEL] Zeigt/Setzt das Level der \v [TRAN_ISO_LEVEL] Zeigt/Setzt das Level der
Verbindungs-Transaktion-Isolation. Verbindungs-Transaktion-Isolation.
(connection transaction isolation) (connection transaction isolation)

8
fine-hsqldb/src/main/java/com/fr/third/org/hsqldb/cmdline/sqltool_de.properties

@ -33,11 +33,11 @@ sqltempfile.fail=Die angegebe SQL konnte nicht in der Datei gespeichert werden.\
rcdata.inlineurl.missing=Das 'url' Element wird für inlineRC benötigt. rcdata.inlineurl.missing=Das 'url' Element wird für inlineRC benötigt.
rcdata.inline.extravars=Nicht unterstützte(s) inlineRC Element(e) angegeben: %{1}. rcdata.inline.extravars=Nicht unterstützte(s) inlineRC Element(e) angegeben: %{1}.
rcdata.inlineusername.missing=Das 'user' Element wird für inlineRC benötigt. rcdata.inlineusername.missing=Das 'user' Element wird für inlineRC benötigt.
rcdata.password.visible=Das 'password' Element muß leer sein. \ rcdata.password.visible=Das 'password' Element mu? leer sein. \
Um ein Passwort zu verwenden lassen Sie das\u000a\ Um ein Passwort zu verwenden lassen Sie das\u000a\
'password' Element weg, sie werden dann separat danach gefragt! 'password' Element weg, sie werden dann separat danach gefragt!
password.readfail=Fehler beim einlesen des Passwortes.\u000aUrsache: %{1} password.readfail=Fehler beim einlesen des Passwortes.\u000aUrsache: %{1}
rcdata.genfromvalues.fail=RCData ließ sich aus den angegebenen Werten nicht erzeugen.\u000aUrsache: %{1} rcdata.genfromvalues.fail=RCData lie? sich aus den angegebenen Werten nicht erzeugen.\u000aUrsache: %{1}
conndata.retrieval.fail=Konnte keine Verbindungsinformationen für urlid "%{1} finden".\u000aUrsache: %{2} conndata.retrieval.fail=Konnte keine Verbindungsinformationen für urlid "%{1} finden".\u000aUrsache: %{2}
jdbc.established=JDBC Verbindung hergestellt zu eine %{1} v. %{2} Datenbank\u000a\ jdbc.established=JDBC Verbindung hergestellt zu eine %{1} v. %{2} Datenbank\u000a\
als "%{3}" mit %{4} Isolation. als "%{3}" mit %{4} Isolation.
@ -165,10 +165,10 @@ describe.table.nonulls=KEINE-NULL
describe.table.precision=PRÄZISION describe.table.precision=PRÄZISION
describe.table.scale=SKALA describe.table.scale=SKALA
logical.unrecognized=Unbekannte logische Operation. logical.unrecognized=Unbekannte logische Operation.
read.toobig=Datenmenge ist zu groß um alles auf einmal einzulesen.\u000a\ read.toobig=Datenmenge ist zu gro? um alles auf einmal einzulesen.\u000a\
Lassen Sie das Programm bitte mit mehr Arbeitsspeicher laufen (Versuchen Sie den 'java -Xm*' Schalter). Lassen Sie das Programm bitte mit mehr Arbeitsspeicher laufen (Versuchen Sie den 'java -Xm*' Schalter).
read.partial=Lese nicht alle Bytes. %{1} Bytes von %{2} werden gelesen. read.partial=Lese nicht alle Bytes. %{1} Bytes von %{2} werden gelesen.
read.convertfail=Wert ist zu groß, um ihn in eine Zeichenkette umzuwandeln. \u000a\ read.convertfail=Wert ist zu gro?, um ihn in eine Zeichenkette umzuwandeln. \u000a\
Lassen Sie das Programm bitte mit mehr Arbeitsspeicher laufen (Versuchen Sie den Java -Xm* Schalter). Lassen Sie das Programm bitte mit mehr Arbeitsspeicher laufen (Versuchen Sie den Java -Xm* Schalter).
dsv.coldelim.present=Tabellendaten enthalten unsere Spaltentrennzeichen '%{1}'. dsv.coldelim.present=Tabellendaten enthalten unsere Spaltentrennzeichen '%{1}'.
dsv.rowdelim.present=Tabellendaten enthalten unsere Zeilentrennzeichen '%{1}'. dsv.rowdelim.present=Tabellendaten enthalten unsere Zeilentrennzeichen '%{1}'.

71
fine-hsqldb/src/main/java/com/fr/third/org/hsqldb/lib/FrameworkLogger.java

@ -50,35 +50,35 @@ import java.lang.reflect.InvocationTargetException;
/** /**
* A logging framework wrapper that supports java.util.logging and log4j. * A logging framework wrapper that supports java.util.logging and log4j.
* <P/> * <p/>
* Logger hierarchies are stored at the Class level. * Logger hierarchies are stored at the Class level.
* Log4j will be used if the Log4j system (not necessarily config files) are * Log4j will be used if the Log4j system (not necessarily config files) are
* found in the runtime classpath. * found in the runtime classpath.
* Otherwise, java.util.logging will be used. * Otherwise, java.util.logging will be used.
* <P/> * <p/>
* This is pretty safe because for use cases where multiple hierarchies * This is pretty safe because for use cases where multiple hierarchies
* are desired, classloader hierarchies will effectively isolate multiple * are desired, classloader hierarchies will effectively isolate multiple
* class-level Logger hierarchies. * class-level Logger hierarchies.
* <P/> * <p/>
* Sad as it is, the java.util.logging facility lacks the most basic * Sad as it is, the java.util.logging facility lacks the most basic
* developer-side and configuration-side capabilities. * developer-side and configuration-side capabilities.
* Besides having a non-scalable discovery system, the designers didn't * Besides having a non-scalable discovery system, the designers didn't
* comprehend the need for a level between WARNING and SEVERE! * comprehend the need for a level between WARNING and SEVERE!
* Since we don't want to require log4j in Classpath, we have to live * Since we don't want to require log4j in Classpath, we have to live
* with these constraints. * with these constraints.
* <P/> * <p/>
* As with all the popular logging frameworks, if you want to capture a * As with all the popular logging frameworks, if you want to capture a
* stack trace, you must use the two-parameters logging methods. * stack trace, you must use the two-parameters logging methods.
* I.e., you must also pass a String, or only toString() from your * I.e., you must also pass a String, or only toString() from your
* throwable will be captured. * throwable will be captured.
* <P/> * <p/>
* Usage example:<CODE><PRE> * Usage example:<CODE><PRE>
* private static FrameworkLogger logger = * private static FrameworkLogger logger =
* FrameworkLogger.getLog(SqlTool.class); * FrameworkLogger.getLog(SqlTool.class);
* ... * ...
* logger.finer("Doing something log-worthy"); * logger.finer("Doing something log-worthy");
* </PRE> </CODE> * </PRE> </CODE>
* * <p>
* <p/> * <p/>
* The system level property <code>hsqldb.reconfig_logging=false</code> is * The system level property <code>hsqldb.reconfig_logging=false</code> is
* required to avoid configuration of java.util.logging. Otherwise * required to avoid configuration of java.util.logging. Otherwise
@ -131,7 +131,8 @@ public class FrameworkLogger {
static { static {
try { try {
reconfigure(); reconfigure();
} catch (SecurityException e) {} } catch (SecurityException e) {
}
} }
/** /**
@ -169,32 +170,32 @@ public class FrameworkLogger {
throws ClassNotFoundException, IllegalAccessException, throws ClassNotFoundException, IllegalAccessException,
NoSuchMethodException, InvocationTargetException { NoSuchMethodException, InvocationTargetException {
Method log4jToLevel = Class.forName(classString).getMethod( Method log4jToLevel = Class.forName(classString).getMethod(
"toLevel", new Class[]{ String.class }); "toLevel", new Class[]{String.class});
jdkToLog4jLevels.put(Level.ALL, jdkToLog4jLevels.put(Level.ALL,
log4jToLevel.invoke(null, log4jToLevel.invoke(null,
new Object[]{ "ALL" })); new Object[]{"ALL"}));
jdkToLog4jLevels.put(Level.FINER, jdkToLog4jLevels.put(Level.FINER,
log4jToLevel.invoke(null, log4jToLevel.invoke(null,
new Object[]{ "DEBUG" })); new Object[]{"DEBUG"}));
jdkToLog4jLevels.put(Level.WARNING, jdkToLog4jLevels.put(Level.WARNING,
log4jToLevel.invoke(null, log4jToLevel.invoke(null,
new Object[]{ "ERROR" })); new Object[]{"ERROR"}));
jdkToLog4jLevels.put(Level.SEVERE, jdkToLog4jLevels.put(Level.SEVERE,
log4jToLevel.invoke(null, log4jToLevel.invoke(null,
new Object[]{ "FATAL" })); new Object[]{"FATAL"}));
jdkToLog4jLevels.put(Level.INFO, jdkToLog4jLevels.put(Level.INFO,
log4jToLevel.invoke(null, log4jToLevel.invoke(null,
new Object[]{ "INFO" })); new Object[]{"INFO"}));
jdkToLog4jLevels.put(Level.OFF, jdkToLog4jLevels.put(Level.OFF,
log4jToLevel.invoke(null, log4jToLevel.invoke(null,
new Object[]{ "OFF" })); new Object[]{"OFF"}));
jdkToLog4jLevels.put(Level.FINEST, jdkToLog4jLevels.put(Level.FINEST,
log4jToLevel.invoke(null, log4jToLevel.invoke(null,
new Object[]{ "TRACE" })); new Object[]{"TRACE"}));
jdkToLog4jLevels.put(Level.WARNING, jdkToLog4jLevels.put(Level.WARNING,
log4jToLevel.invoke(null, log4jToLevel.invoke(null,
new Object[]{ "WARN" })); new Object[]{"WARN"}));
} }
static void reconfigure() { static void reconfigure() {
@ -219,9 +220,9 @@ public class FrameworkLogger {
try { try {
// log4j v2 available? // log4j v2 available?
log4jLoggerClass = Class.forName( log4jLoggerClass = Class.forName(
"org.apache.logging.log4j.Logger"); "com.fr.third.apache.logging.log4j.Logger");
log4jManagerClass = Class.forName( log4jManagerClass = Class.forName(
"org.apache.logging.log4j.LogManager"); "com.fr.third.apache.logging.log4j.LogManager");
} catch (Exception e) { } catch (Exception e) {
// The class will only load successfully if Log4j v2 thinks it is // The class will only load successfully if Log4j v2 thinks it is
@ -232,15 +233,15 @@ public class FrameworkLogger {
// Attempt to configure log4j v2 // Attempt to configure log4j v2
if (log4jLoggerClass != null) { if (log4jLoggerClass != null) {
try { try {
populateJdkToLog4jLevels("org.apache.logging.log4j.Level"); populateJdkToLog4jLevels("com.fr.third.apache.logging.log4j.Level");
log4jLogMethod = log4jLoggerClass.getMethod("log", log4jLogMethod = log4jLoggerClass.getMethod("log",
new Class[] { new Class[]{
Class.forName("org.apache.logging.log4j.Level"), Class.forName("com.fr.third.apache.logging.log4j.Level"),
Object.class, Throwable.class Object.class, Throwable.class
}); });
log4jGetLogger = log4jManagerClass.getMethod("getLogger", log4jGetLogger = log4jManagerClass.getMethod("getLogger",
new Class[]{ String.class }); new Class[]{String.class});
// This last object is what we toggle on to generate either // This last object is what we toggle on to generate either
// Log4j or Jdk Logger objects (to wrap). // Log4j or Jdk Logger objects (to wrap).
@ -272,7 +273,7 @@ public class FrameworkLogger {
try { try {
// log4j v1 available? // log4j v1 available?
log4jLoggerClass = Class.forName("org.apache.log4j.Logger"); log4jLoggerClass = Class.forName("com.fr.third.apache.log4j.Logger");
log4jManagerClass = log4jLoggerClass; log4jManagerClass = log4jLoggerClass;
} catch (Exception e) { } catch (Exception e) {
@ -284,15 +285,15 @@ public class FrameworkLogger {
// Attempt to configure log4j v1 // Attempt to configure log4j v1
if (log4jLoggerClass != null) { if (log4jLoggerClass != null) {
try { try {
populateJdkToLog4jLevels("org.apache.log4j.Level"); populateJdkToLog4jLevels("com.fr.third.apache.log4j.Level");
log4jLogMethod = log4jLoggerClass.getMethod("log", log4jLogMethod = log4jLoggerClass.getMethod("log",
new Class[] { new Class[]{
String.class, Class.forName("org.apache.log4j.Priority"), String.class, Class.forName("com.fr.third.apache.log4j.Priority"),
Object.class, Throwable.class Object.class, Throwable.class
}); });
log4jGetLogger = log4jManagerClass.getMethod("getLogger", log4jGetLogger = log4jManagerClass.getMethod("getLogger",
new Class[]{ String.class }); new Class[]{String.class});
// This last object is what we toggle on to generate either // This last object is what we toggle on to generate either
// Log4j or Jdk Logger objects (to wrap). // Log4j or Jdk Logger objects (to wrap).
callerFqcnAvailable = true; callerFqcnAvailable = true;
@ -350,7 +351,7 @@ public class FrameworkLogger {
lm.readConfiguration(istream); lm.readConfiguration(istream);
Logger cmdlineLogger = Logger.getLogger("org.hsqldb.cmdline"); Logger cmdlineLogger = Logger.getLogger("com.fr.third.org.hsqldb.cmdline");
cmdlineLogger.addHandler(consoleHandler); cmdlineLogger.addHandler(consoleHandler);
cmdlineLogger.setUseParentHandlers(false); cmdlineLogger.setUseParentHandlers(false);
@ -397,7 +398,7 @@ public class FrameworkLogger {
} else { } else {
try { try {
log4jLogger = log4jGetLogger.invoke(null, log4jLogger = log4jGetLogger.invoke(null,
new Object[]{ s }); new Object[]{s});
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException( throw new RuntimeException(
"Failed to instantiate Log4j Logger", e); "Failed to instantiate Log4j Logger", e);
@ -412,7 +413,7 @@ public class FrameworkLogger {
/** /**
* User's entry-point into this logging system. * User's entry-point into this logging system.
* <P/> * <p/>
* You normally want to work with static (class-level) pointers to * You normally want to work with static (class-level) pointers to
* logger instances, for performance efficiency. * logger instances, for performance efficiency.
* See the class-level JavaDoc for a usage example. * See the class-level JavaDoc for a usage example.
@ -508,10 +509,10 @@ public class FrameworkLogger {
} else { } else {
try { try {
log4jLogMethod.invoke(log4jLogger, callerFqcnAvailable log4jLogMethod.invoke(log4jLogger, callerFqcnAvailable
? new Object[] { ? new Object[]{
skipClass.getName(), jdkToLog4jLevels.get(level), skipClass.getName(), jdkToLog4jLevels.get(level),
message, t} message, t}
: new Object[] { : new Object[]{
jdkToLog4jLevels.get(level), message, t} jdkToLog4jLevels.get(level), message, t}
); );
} catch (Exception e) { } catch (Exception e) {
@ -539,10 +540,10 @@ public class FrameworkLogger {
} else { } else {
try { try {
log4jLogMethod.invoke(log4jLogger, callerFqcnAvailable log4jLogMethod.invoke(log4jLogger, callerFqcnAvailable
? new Object[] { ? new Object[]{
FrameworkLogger.class.getName(), FrameworkLogger.class.getName(),
jdkToLog4jLevels.get(level), message, null} jdkToLog4jLevels.get(level), message, null}
: new Object[] { : new Object[]{
jdkToLog4jLevels.get(level), message, null} jdkToLog4jLevels.get(level), message, null}
); );
@ -679,7 +680,7 @@ public class FrameworkLogger {
/** /**
* Whether this JVM is configured with java.util.logging defaults. * Whether this JVM is configured with java.util.logging defaults.
* * <p>
* If the JRE-provided config file is not in the expected place, then * If the JRE-provided config file is not in the expected place, then
* we return false. * we return false.
*/ */

46
fine-hsqldb/src/main/java/com/fr/third/org/hsqldb/resources/sql-state-messages_es.properties

@ -60,7 +60,7 @@
0302=S0502 no se ha indicado valor para el campo 0302=S0502 no se ha indicado valor para el campo
0303=S0503 separador con texto de longitud cero 0303=S0503 separador con texto de longitud cero
0304=S0504 0304=S0504
0320=S0521 la operación no está permitida en una tabla de texto con datos 0320=S0521 la operación no est? permitida en una tabla de texto con datos
0321=S0522 sentencia inválida - es necesario indicar tabla de texto 0321=S0522 sentencia inválida - es necesario indicar tabla de texto
0331=S0531 table de texto error de codificación / decodificación 0331=S0531 table de texto error de codificación / decodificación
0332=S0532 UTF-16 codificación 0332=S0532 UTF-16 codificación
@ -74,7 +74,7 @@
0403=S0504 La versión del cliente '$$' es incompatible. \ 0403=S0504 La versión del cliente '$$' es incompatible. \
Se requiere una versión de protocolo de red HSQLDB '$$' Se requiere una versión de protocolo de red HSQLDB '$$'
0404=S0504 El cliente de red no es un controlador JDBC HSQLDB 0404=S0504 El cliente de red no es un controlador JDBC HSQLDB
0405=S0504 El cliente está usando el protocolo HSQLDB http en lugar de hsql 0405=S0504 El cliente est? usando el protocolo HSQLDB http en lugar de hsql
0406=S0504 Lectura incompleta de datos personalizados 0406=S0504 Lectura incompleta de datos personalizados
0407=S1000 Rutas de ficheros para la base de datos no son correctas 0407=S1000 Rutas de ficheros para la base de datos no son correctas
@ -89,8 +89,8 @@
0451=S1000 Fallo al obtener un bloqueo en la base de datos 0451=S1000 Fallo al obtener un bloqueo en la base de datos
0452=S1000 Error de lectura/escritura de fichero 0452=S1000 Error de lectura/escritura de fichero
0453=S1000 Versión de fichero de base de datos errónea 0453=S1000 Versión de fichero de base de datos errónea
0454=S1000 data file is modified but backup file does not exist 0454=S1000 .data file is modified but .backup file does not exist
0455=S1000 La base de datos está en modo solo lectura 0455=S1000 La base de datos est? en modo solo lectura
0456=S1000 La tabla de datos es de solo lectura 0456=S1000 La tabla de datos es de solo lectura
0457=S1000 Acceso denegado 0457=S1000 Acceso denegado
0458=S1000 Error general 0458=S1000 Error general
@ -160,7 +160,7 @@
1215=0700F error de sentencia SQL dinámica: DATETIME_INTERVAL_CODE incorrecto 1215=0700F error de sentencia SQL dinámica: DATETIME_INTERVAL_CODE incorrecto
# HSQLDB # HSQLDB
1251=07501 sentencia SQL está cerrada 1251=07501 sentencia SQL est? cerrada
1252=07502 sentencia SQL es incorrecta 1252=07502 sentencia SQL es incorrecta
1253=07503 sentencia SQL no devuelve el número de filas 1253=07503 sentencia SQL no devuelve el número de filas
1254=07504 sentencia SQL no devuelve un conjunto de datos ('result set') 1254=07504 sentencia SQL no devuelve un conjunto de datos ('result set')
@ -203,7 +203,7 @@
# HSQLDB locator # HSQLDB locator
1852=0F502 lob antiguo y ya no es válido 1852=0F502 lob antiguo y ya no es válido
1853=0F503 lob - canal de datos ('stream') está cerrado 1853=0F503 lob - canal de datos ('stream') est? cerrado
# resignal when handler not active # resignal when handler not active
1900=0K000 señal reenviada cuando el canal no estaba activo 1900=0K000 señal reenviada cuando el canal no estaba activo
@ -351,9 +351,9 @@
# invalid cursor state # invalid cursor state
3600=24000 estado del cursor incorrecto 3600=24000 estado del cursor incorrecto
3601=24501 estado del cursor incorrecto: cursor indicado no está abierto 3601=24501 estado del cursor incorrecto: cursor indicado no est? abierto
3602=24502 estado del cursor incorrecto: cursor indicado ya estaba abierto 3602=24502 estado del cursor incorrecto: cursor indicado ya estaba abierto
3603=24504 estado del cursor incorrecto: cursor indicado no está posicionado en una fila para sentencia UPDATE, DELETE, SET, o GET 3603=24504 estado del cursor incorrecto: cursor indicado no est? posicionado en una fila para sentencia UPDATE, DELETE, SET, o GET
3604=24513 estado del cursor incorrecto: no se puede hacer FETCH NEXT, PRIOR, CURRENT, o RELATIVE, ya que la posicón del cursor es desconocida 3604=24513 estado del cursor incorrecto: no se puede hacer FETCH NEXT, PRIOR, CURRENT, o RELATIVE, ya que la posicón del cursor es desconocida
3605=24514 estado del cursor incorrecto: cursor desactivado por un error previo 3605=24514 estado del cursor incorrecto: cursor desactivado por un error previo
3606=24515 estado del cursor incorrecto: todas las columnas se deben informar antes de llamar a INSERT 3606=24515 estado del cursor incorrecto: todas las columnas se deben informar antes de llamar a INSERT
@ -402,10 +402,10 @@
# SQL routine exception # SQL routine exception
4600=2F000 excepción en rutina SQL 4600=2F000 excepción en rutina SQL
4602=2F002 excepción en rutina SQL: modificar datos SQL no está permitido 4602=2F002 excepción en rutina SQL: modificar datos SQL no est? permitido
4603=2F003 excepción en rutina SQL: sentencia SQL ejecutada prohibida 4603=2F003 excepción en rutina SQL: sentencia SQL ejecutada prohibida
4604=2F004 excepción en rutina SQL: leer datos SQL no está permitido 4604=2F004 excepción en rutina SQL: leer datos SQL no est? permitido
4605=2F005 excepción en rutina SQL: la función no ejecutó una sentencia RETURN 4605=2F005 excepción en rutina SQL: la función no ejecut? una sentencia RETURN
# invalid collation name # invalid collation name
4650=2H000 nombre de juego de caracteres ('collation') incorrecto 4650=2H000 nombre de juego de caracteres ('collation') incorrecto
@ -438,9 +438,9 @@
# external routine exception # external routine exception
4800=38000 excepcón en rutina externa 4800=38000 excepcón en rutina externa
4801=38001 excepcón en rutina externa: SQL contenido no permitido 4801=38001 excepcón en rutina externa: SQL contenido no permitido
4802=38002 excepcón en rutina externa: cambios en datos SQL no está permitido 4802=38002 excepcón en rutina externa: cambios en datos SQL no est? permitido
4803=38003 excepcón en rutina externa: sentencia SQL ejecutada prohibida 4803=38003 excepcón en rutina externa: sentencia SQL ejecutada prohibida
4804=38004 excepcón en rutina externa: leer datos SQL no está permitido 4804=38004 excepcón en rutina externa: leer datos SQL no est? permitido
# external routine invocation exception # external routine invocation exception
4810=39000 excepcón al ejecutar rutina externa 4810=39000 excepcón al ejecutar rutina externa
@ -495,13 +495,13 @@
5521=42521 SET DEFAULT requiere una expresión para el valor por defecto de la columna 5521=42521 SET DEFAULT requiere una expresión para el valor por defecto de la columna
5522=42522 ya existe una restricción única, UNIQUE, para este conjunto de columnas 5522=42522 ya existe una restricción única, UNIQUE, para este conjunto de columnas
5523=42523 la tabla no tiene clave primária 5523=42523 la tabla no tiene clave primária
5524=42524 la definición de esta restricción no está permitida 5524=42524 la definición de esta restricción no est? permitida
5525=42525 la definición de identidad ('identity') no está permitida 5525=42525 la definición de identidad ('identity') no est? permitida
5526=42526 la columna forma parte de la clave primaria 5526=42526 la columna forma parte de la clave primaria
5527=42527 la columna forma parte de una restricción 5527=42527 la columna forma parte de una restricción
5528=42528 ya existe una clave foránea ('FOREIGN KEY') para este conjunto de columnas 5528=42528 ya existe una clave foránea ('FOREIGN KEY') para este conjunto de columnas
5529=42529 no existe una restricción única, ('UNIQUE') en las columnas indicadas 5529=42529 no existe una restricción única, ('UNIQUE') en las columnas indicadas
5530=42530 la definición de esta clave primária no está permitida 5530=42530 la definición de esta clave primária no est? permitida
5531=42531 se necesita una expresión para el valor por defecto 5531=42531 se necesita una expresión para el valor por defecto
5532=42532 ya existe una clave primária 5532=42532 ya existe una clave primária
5533=42533 es referenciada por una clave foránea ('FOREIGN KEY') 5533=42533 es referenciada por una clave foránea ('FOREIGN KEY')
@ -509,10 +509,10 @@
# other definition issues # other definition issues
5535=42535 no es una columna identidad ('identity') 5535=42535 no es una columna identidad ('identity')
5536=42536 la columna está referenciada en 5536=42536 la columna est? referenciada en
5537=42537 no se puede usar WITH CHECK OPTION para una vista de sólo lectura 5537=42537 no se puede usar WITH CHECK OPTION para una vista de sólo lectura
5538=42538 la definición del disparador ('TRIGGER') no es compatible con la tabla 5538=42538 la definición del disparador ('TRIGGER') no es compatible con la tabla
5539=42539 no se puede borrar un usuario mientras esté conectado 5539=42539 no se puede borrar un usuario mientras est? conectado
# DML # DML
5541=42541 se requiere la palabra DEFAULT 5541=42541 se requiere la palabra DEFAULT
@ -543,11 +543,11 @@
5570=42570 la concatenación excede el máximo de longitud que permite el tipo de dato 5570=42570 la concatenación excede el máximo de longitud que permite el tipo de dato
# #
5571=42571 el literal NULL no está permitido 5571=42571 el literal NULL no est? permitido
5572=42572 expresión GROUP BY incorrecta 5572=42572 expresión GROUP BY incorrecta
5573=42573 expresión HAVING incorrecta 5573=42573 expresión HAVING incorrecta
5574=42574 la expresión no está en una agregación o columnas del GROUP BY 5574=42574 la expresión no est? en una agregación o columnas del GROUP BY
5575=42575 el marcador del parámetro no está permitido 5575=42575 el marcador del parámetro no est? permitido
5576=42576 expresión ORDER BY incorrecta 5576=42576 expresión ORDER BY incorrecta
5577=42577 nombre de columna duplicada en la lista de columnas 5577=42577 nombre de columna duplicada en la lista de columnas
5578=42578 nombre de columna duplicada en la tabla derivada 5578=42578 nombre de columna duplicada en la tabla derivada
@ -590,6 +590,8 @@
5610=42610 declaración incorrecta 'aggregate function' 5610=42610 declaración incorrecta 'aggregate function'
5611=42611 type incompatible with declared return type 5611=42611 type incompatible with declared return type
5612=42612 SQL exception already used 5612=42612 SQL exception already used
5613=42613 wildcard * not allowed in routine, view or trigger definition
5614=42614 nombre de par?metro duplicado
# with check option violation # with check option violation
5700=44000 violación de opción 'with check option' 5700=44000 violación de opción 'with check option'
@ -651,7 +653,7 @@
# datalink exception # datalink exception
6700=HW000 excepción en conexión de datos 6700=HW000 excepción en conexión de datos
6701=HW001 excepción en conexión de datos: fichero externo no conectado 6701=HW001 excepción en conexión de datos: fichero externo no conectado
6702=HW002 excepción en conexión de datos: fichero externo ya está conectado 6702=HW002 excepción en conexión de datos: fichero externo ya est? conectado
6703=HW003 excepción en conexión de datos: el fichero de referencia no existe 6703=HW003 excepción en conexión de datos: el fichero de referencia no existe
6704=HW004 excepción en conexión de datos: palabra ('token') de escritura incorrecto 6704=HW004 excepción en conexión de datos: palabra ('token') de escritura incorrecto
6705=HW005 excepción en conexión de datos: construcción de la conexión de datos incorrecto 6705=HW005 excepción en conexión de datos: construcción de la conexión de datos incorrecto

1
fine-spring/readme.md

@ -2,3 +2,4 @@
2 fine-spring内容见https://kms.fineres.com/pages/viewpage.action?pageId=152798513<br> 2 fine-spring内容见https://kms.fineres.com/pages/viewpage.action?pageId=152798513<br>
3 定制内容处均有"// 定制"注释<br> 3 定制内容处均有"// 定制"注释<br>
4 去除对jackson的ObjectMapper的支持:DEC-17331<br> 4 去除对jackson的ObjectMapper的支持:DEC-17331<br>
5、删除com.fr.third.springframework.remoting.caucho ;com.fr.third.springframework.remoting.httpinvoker; com.fr.third.springframework.remoting.rmi.*<br>

4
fine-spring/src/main/java/com/fr/third/springframework/ejb/access/AbstractRemoteSlsbInvokerInterceptor.java

@ -22,13 +22,11 @@ import java.rmi.RemoteException;
import javax.ejb.EJBHome; import javax.ejb.EJBHome;
import javax.ejb.EJBObject; import javax.ejb.EJBObject;
import javax.naming.NamingException; import javax.naming.NamingException;
import javax.rmi.PortableRemoteObject;
import org.aopalliance.intercept.MethodInvocation; import org.aopalliance.intercept.MethodInvocation;
import com.fr.third.springframework.remoting.RemoteConnectFailureException; import com.fr.third.springframework.remoting.RemoteConnectFailureException;
import com.fr.third.springframework.remoting.RemoteLookupFailureException; import com.fr.third.springframework.remoting.RemoteLookupFailureException;
import com.fr.third.springframework.remoting.rmi.RmiClientInterceptorUtils;
/** /**
* Base class for interceptors proxying remote Stateless Session Beans. * Base class for interceptors proxying remote Stateless Session Beans.
@ -162,7 +160,7 @@ public abstract class AbstractRemoteSlsbInvokerInterceptor extends AbstractSlsbI
* @see com.fr.third.springframework.remoting.rmi.RmiClientInterceptorUtils#isConnectFailure * @see com.fr.third.springframework.remoting.rmi.RmiClientInterceptorUtils#isConnectFailure
*/ */
protected boolean isConnectFailure(RemoteException ex) { protected boolean isConnectFailure(RemoteException ex) {
return RmiClientInterceptorUtils.isConnectFailure(ex); throw new UnsupportedOperationException();
} }
private Object handleRemoteConnectFailure(MethodInvocation invocation, Exception ex) throws Throwable { private Object handleRemoteConnectFailure(MethodInvocation invocation, Exception ex) throws Throwable {

40
fine-spring/src/main/java/com/fr/third/springframework/ejb/access/SimpleRemoteSlsbInvokerInterceptor.java

@ -16,17 +16,12 @@
package com.fr.third.springframework.ejb.access; package com.fr.third.springframework.ejb.access;
import java.lang.reflect.InvocationTargetException; import com.fr.third.springframework.beans.factory.DisposableBean;
import java.rmi.RemoteException;
import javax.ejb.CreateException;
import javax.ejb.EJBObject;
import javax.naming.NamingException;
import org.aopalliance.intercept.MethodInvocation; import org.aopalliance.intercept.MethodInvocation;
import com.fr.third.springframework.beans.factory.DisposableBean; import javax.ejb.EJBObject;
import com.fr.third.springframework.remoting.RemoteLookupFailureException; import javax.naming.NamingException;
import com.fr.third.springframework.remoting.rmi.RmiClientInterceptorUtils; import java.lang.reflect.InvocationTargetException;
/** /**
* Basic invoker for a remote Stateless Session Bean. * Basic invoker for a remote Stateless Session Bean.
@ -92,32 +87,7 @@ public class SimpleRemoteSlsbInvokerInterceptor extends AbstractRemoteSlsbInvoke
*/ */
@Override @Override
protected Object doInvoke(MethodInvocation invocation) throws Throwable { protected Object doInvoke(MethodInvocation invocation) throws Throwable {
Object ejb = null; throw new UnsupportedOperationException();
try {
ejb = getSessionBeanInstance();
return RmiClientInterceptorUtils.invokeRemoteMethod(invocation, ejb);
}
catch (NamingException ex) {
throw new RemoteLookupFailureException("Failed to locate remote EJB [" + getJndiName() + "]", ex);
}
catch (InvocationTargetException ex) {
Throwable targetEx = ex.getTargetException();
if (targetEx instanceof RemoteException) {
RemoteException rex = (RemoteException) targetEx;
throw RmiClientInterceptorUtils.convertRmiAccessException(
invocation.getMethod(), rex, isConnectFailure(rex), getJndiName());
}
else if (targetEx instanceof CreateException) {
throw RmiClientInterceptorUtils.convertRmiAccessException(
invocation.getMethod(), targetEx, "Could not create remote EJB [" + getJndiName() + "]");
}
throw targetEx;
}
finally {
if (ejb instanceof EJBObject) {
releaseSessionBeanInstance((EJBObject) ejb);
}
}
} }
/** /**

194
fine-spring/src/main/java/com/fr/third/springframework/remoting/caucho/BurlapClientInterceptor.java

@ -1,194 +0,0 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fr.third.springframework.remoting.caucho;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.UndeclaredThrowableException;
import java.net.ConnectException;
import java.net.MalformedURLException;
import com.caucho.burlap.client.BurlapProxyFactory;
import com.caucho.burlap.client.BurlapRuntimeException;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import com.fr.third.springframework.remoting.RemoteAccessException;
import com.fr.third.springframework.remoting.RemoteConnectFailureException;
import com.fr.third.springframework.remoting.RemoteLookupFailureException;
import com.fr.third.springframework.remoting.RemoteProxyFailureException;
import com.fr.third.springframework.remoting.support.UrlBasedRemoteAccessor;
import com.fr.third.springframework.util.Assert;
/**
* {@link org.aopalliance.intercept.MethodInterceptor} for accessing a Burlap service.
* Supports authentication via username and password.
* The service URL must be an HTTP URL exposing a Burlap service.
*
* <p>Burlap is a slim, XML-based RPC protocol.
* For information on Burlap, see the
* <a href="https://www.caucho.com/burlap">Burlap website</a>
*
* <p>Note: There is no requirement for services accessed with this proxy factory
* to have been exported using Spring's {@link BurlapServiceExporter}, as there is
* no special handling involved. As a consequence, you can also access services that
* have been exported using Caucho's {@link com.caucho.burlap.server.BurlapServlet}.
*
* @author Juergen Hoeller
* @since 29.09.2003
* @see #setServiceInterface
* @see #setServiceUrl
* @see #setUsername
* @see #setPassword
* @see BurlapServiceExporter
* @see BurlapProxyFactoryBean
* @see com.caucho.burlap.client.BurlapProxyFactory
* @see com.caucho.burlap.server.BurlapServlet
* @deprecated as of Spring 4.0, since Burlap hasn't evolved in years
* and is effectively retired (in contrast to its sibling Hessian)
*/
@Deprecated
public class BurlapClientInterceptor extends UrlBasedRemoteAccessor implements MethodInterceptor {
private BurlapProxyFactory proxyFactory = new BurlapProxyFactory();
private Object burlapProxy;
/**
* Set the BurlapProxyFactory instance to use.
* If not specified, a default BurlapProxyFactory will be created.
* <p>Allows to use an externally configured factory instance,
* in particular a custom BurlapProxyFactory subclass.
*/
public void setProxyFactory(BurlapProxyFactory proxyFactory) {
this.proxyFactory = (proxyFactory != null ? proxyFactory : new BurlapProxyFactory());
}
/**
* Set the username that this factory should use to access the remote service.
* Default is none.
* <p>The username will be sent by Burlap via HTTP Basic Authentication.
* @see com.caucho.burlap.client.BurlapProxyFactory#setUser
*/
public void setUsername(String username) {
this.proxyFactory.setUser(username);
}
/**
* Set the password that this factory should use to access the remote service.
* Default is none.
* <p>The password will be sent by Burlap via HTTP Basic Authentication.
* @see com.caucho.burlap.client.BurlapProxyFactory#setPassword
*/
public void setPassword(String password) {
this.proxyFactory.setPassword(password);
}
/**
* Set whether overloaded methods should be enabled for remote invocations.
* Default is "false".
* @see com.caucho.burlap.client.BurlapProxyFactory#setOverloadEnabled
*/
public void setOverloadEnabled(boolean overloadEnabled) {
this.proxyFactory.setOverloadEnabled(overloadEnabled);
}
@Override
public void afterPropertiesSet() {
super.afterPropertiesSet();
prepare();
}
/**
* Initialize the Burlap proxy for this interceptor.
* @throws RemoteLookupFailureException if the service URL is invalid
*/
public void prepare() throws RemoteLookupFailureException {
try {
this.burlapProxy = createBurlapProxy(this.proxyFactory);
}
catch (MalformedURLException ex) {
throw new RemoteLookupFailureException("Service URL [" + getServiceUrl() + "] is invalid", ex);
}
}
/**
* Create the Burlap proxy that is wrapped by this interceptor.
* @param proxyFactory the proxy factory to use
* @return the Burlap proxy
* @throws MalformedURLException if thrown by the proxy factory
* @see com.caucho.burlap.client.BurlapProxyFactory#create
*/
protected Object createBurlapProxy(BurlapProxyFactory proxyFactory) throws MalformedURLException {
Assert.notNull(getServiceInterface(), "Property 'serviceInterface' is required");
return proxyFactory.create(getServiceInterface(), getServiceUrl());
}
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
if (this.burlapProxy == null) {
throw new IllegalStateException("BurlapClientInterceptor is not properly initialized - " +
"invoke 'prepare' before attempting any operations");
}
ClassLoader originalClassLoader = overrideThreadContextClassLoader();
try {
return invocation.getMethod().invoke(this.burlapProxy, invocation.getArguments());
}
catch (InvocationTargetException ex) {
Throwable targetEx = ex.getTargetException();
if (targetEx instanceof BurlapRuntimeException) {
Throwable cause = targetEx.getCause();
throw convertBurlapAccessException(cause != null ? cause : targetEx);
}
else if (targetEx instanceof UndeclaredThrowableException) {
UndeclaredThrowableException utex = (UndeclaredThrowableException) targetEx;
throw convertBurlapAccessException(utex.getUndeclaredThrowable());
}
else {
throw targetEx;
}
}
catch (Throwable ex) {
throw new RemoteProxyFailureException(
"Failed to invoke Burlap proxy for remote service [" + getServiceUrl() + "]", ex);
}
finally {
resetThreadContextClassLoader(originalClassLoader);
}
}
/**
* Convert the given Burlap access exception to an appropriate
* Spring RemoteAccessException.
* @param ex the exception to convert
* @return the RemoteAccessException to throw
*/
protected RemoteAccessException convertBurlapAccessException(Throwable ex) {
if (ex instanceof ConnectException) {
return new RemoteConnectFailureException(
"Cannot connect to Burlap remote service at [" + getServiceUrl() + "]", ex);
}
else {
return new RemoteAccessException(
"Cannot access Burlap remote service at [" + getServiceUrl() + "]", ex);
}
}
}

97
fine-spring/src/main/java/com/fr/third/springframework/remoting/caucho/BurlapExporter.java

@ -1,97 +0,0 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fr.third.springframework.remoting.caucho;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import com.caucho.burlap.io.BurlapInput;
import com.caucho.burlap.io.BurlapOutput;
import com.caucho.burlap.server.BurlapSkeleton;
import com.fr.third.springframework.beans.factory.InitializingBean;
import com.fr.third.springframework.remoting.support.RemoteExporter;
import com.fr.third.springframework.util.Assert;
/**
* General stream-based protocol exporter for a Burlap endpoint.
*
* <p>Burlap is a slim, XML-based RPC protocol.
* For information on Burlap, see the
* <a href="https://www.caucho.com/burlap">Burlap website</a>.
* This exporter requires Burlap 3.x.
*
* @author Juergen Hoeller
* @since 2.5.1
* @see #invoke(java.io.InputStream, java.io.OutputStream)
* @see BurlapServiceExporter
* @see SimpleBurlapServiceExporter
* @deprecated as of Spring 4.0, since Burlap hasn't evolved in years
* and is effectively retired (in contrast to its sibling Hessian)
*/
@Deprecated
public class BurlapExporter extends RemoteExporter implements InitializingBean {
private BurlapSkeleton skeleton;
@Override
public void afterPropertiesSet() {
prepare();
}
/**
* Initialize this service exporter.
*/
public void prepare() {
checkService();
checkServiceInterface();
this.skeleton = new BurlapSkeleton(getProxyForService(), getServiceInterface());
}
/**
* Perform an invocation on the exported object.
* @param inputStream the request stream
* @param outputStream the response stream
* @throws Throwable if invocation failed
*/
public void invoke(InputStream inputStream, OutputStream outputStream) throws Throwable {
Assert.notNull(this.skeleton, "Burlap exporter has not been initialized");
ClassLoader originalClassLoader = overrideThreadContextClassLoader();
try {
this.skeleton.invoke(new BurlapInput(inputStream), new BurlapOutput(outputStream));
}
finally {
try {
inputStream.close();
}
catch (IOException ex) {
// ignore
}
try {
outputStream.close();
}
catch (IOException ex) {
// ignore
}
resetThreadContextClassLoader(originalClassLoader);
}
}
}

73
fine-spring/src/main/java/com/fr/third/springframework/remoting/caucho/BurlapProxyFactoryBean.java

@ -1,73 +0,0 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fr.third.springframework.remoting.caucho;
import com.fr.third.springframework.aop.framework.ProxyFactory;
import com.fr.third.springframework.beans.factory.FactoryBean;
/**
* {@link FactoryBean} for Burlap proxies. Exposes the proxied service
* for use as a bean reference, using the specified service interface.
*
* <p>Burlap is a slim, XML-based RPC protocol.
* For information on Burlap, see the
* <a href="https://www.caucho.com/burlap">Burlap website</a>
*
* <p>The service URL must be an HTTP URL exposing a Burlap service.
* For details, see the {@link BurlapClientInterceptor} javadoc.
*
* @author Juergen Hoeller
* @since 13.05.2003
* @see #setServiceInterface
* @see #setServiceUrl
* @see BurlapClientInterceptor
* @see BurlapServiceExporter
* @see com.fr.third.springframework.remoting.caucho.HessianProxyFactoryBean
* @see com.fr.third.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean
* @see com.fr.third.springframework.remoting.rmi.RmiProxyFactoryBean
* @deprecated as of Spring 4.0, since Burlap hasn't evolved in years
* and is effectively retired (in contrast to its sibling Hessian)
*/
@Deprecated
public class BurlapProxyFactoryBean extends BurlapClientInterceptor implements FactoryBean<Object> {
private Object serviceProxy;
@Override
public void afterPropertiesSet() {
super.afterPropertiesSet();
this.serviceProxy = new ProxyFactory(getServiceInterface(), this).getProxy(getBeanClassLoader());
}
@Override
public Object getObject() {
return this.serviceProxy;
}
@Override
public Class<?> getObjectType() {
return getServiceInterface();
}
@Override
public boolean isSingleton() {
return true;
}
}

76
fine-spring/src/main/java/com/fr/third/springframework/remoting/caucho/BurlapServiceExporter.java

@ -1,76 +0,0 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fr.third.springframework.remoting.caucho;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.fr.third.springframework.web.HttpRequestHandler;
import com.fr.third.springframework.web.HttpRequestMethodNotSupportedException;
import com.fr.third.springframework.web.util.NestedServletException;
/**
* Servlet-API-based HTTP request handler that exports the specified service bean
* as Burlap service endpoint, accessible via a Burlap proxy.
*
* <p><b>Note:</b> Spring also provides an alternative version of this exporter,
* for Sun's JRE 1.6 HTTP server: {@link SimpleBurlapServiceExporter}.
*
* <p>Burlap is a slim, XML-based RPC protocol.
* For information on Burlap, see the
* <a href="https://www.caucho.com/burlap">Burlap website</a>.
* This exporter requires Burlap 3.x.
*
* <p>Note: Burlap services exported with this class can be accessed by
* any Burlap client, as there isn't any special handling involved.
*
* @author Juergen Hoeller
* @since 13.05.2003
* @see BurlapClientInterceptor
* @see BurlapProxyFactoryBean
* @see com.fr.third.springframework.remoting.caucho.HessianServiceExporter
* @see com.fr.third.springframework.remoting.httpinvoker.HttpInvokerServiceExporter
* @see com.fr.third.springframework.remoting.rmi.RmiServiceExporter
* @deprecated as of Spring 4.0, since Burlap hasn't evolved in years
* and is effectively retired (in contrast to its sibling Hessian)
*/
@Deprecated
public class BurlapServiceExporter extends BurlapExporter implements HttpRequestHandler {
/**
* Processes the incoming Burlap request and creates a Burlap response.
*/
@Override
public void handleRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
if (!"POST".equals(request.getMethod())) {
throw new HttpRequestMethodNotSupportedException(request.getMethod(),
new String[] {"POST"}, "BurlapServiceExporter only supports POST requests");
}
try {
invoke(request.getInputStream(), response.getOutputStream());
}
catch (Throwable ex) {
throw new NestedServletException("Burlap skeleton invocation failed", ex);
}
}
}

297
fine-spring/src/main/java/com/fr/third/springframework/remoting/caucho/HessianClientInterceptor.java

@ -1,297 +0,0 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fr.third.springframework.remoting.caucho;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.UndeclaredThrowableException;
import java.net.ConnectException;
import java.net.MalformedURLException;
import com.caucho.hessian.HessianException;
import com.caucho.hessian.client.HessianConnectionException;
import com.caucho.hessian.client.HessianConnectionFactory;
import com.caucho.hessian.client.HessianProxyFactory;
import com.caucho.hessian.client.HessianRuntimeException;
import com.caucho.hessian.io.SerializerFactory;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import com.fr.third.springframework.remoting.RemoteAccessException;
import com.fr.third.springframework.remoting.RemoteConnectFailureException;
import com.fr.third.springframework.remoting.RemoteLookupFailureException;
import com.fr.third.springframework.remoting.RemoteProxyFailureException;
import com.fr.third.springframework.remoting.support.UrlBasedRemoteAccessor;
import com.fr.third.springframework.util.Assert;
/**
* {@link org.aopalliance.intercept.MethodInterceptor} for accessing a Hessian service.
* Supports authentication via username and password.
* The service URL must be an HTTP URL exposing a Hessian service.
*
* <p>Hessian is a slim, binary RPC protocol.
* For information on Hessian, see the
* <a href="http://hessian.caucho.com">Hessian website</a>
* <b>Note: As of Spring 4.0, this client requires Hessian 4.0 or above.</b>
*
* <p>Note: There is no requirement for services accessed with this proxy factory
* to have been exported using Spring's {@link HessianServiceExporter}, as there is
* no special handling involved. As a consequence, you can also access services that
* have been exported using Caucho's {@link com.caucho.hessian.server.HessianServlet}.
*
* @author Juergen Hoeller
* @since 29.09.2003
* @see #setServiceInterface
* @see #setServiceUrl
* @see #setUsername
* @see #setPassword
* @see HessianServiceExporter
* @see HessianProxyFactoryBean
* @see com.caucho.hessian.client.HessianProxyFactory
* @see com.caucho.hessian.server.HessianServlet
*/
public class HessianClientInterceptor extends UrlBasedRemoteAccessor implements MethodInterceptor {
private HessianProxyFactory proxyFactory = new HessianProxyFactory();
private Object hessianProxy;
/**
* Set the HessianProxyFactory instance to use.
* If not specified, a default HessianProxyFactory will be created.
* <p>Allows to use an externally configured factory instance,
* in particular a custom HessianProxyFactory subclass.
*/
public void setProxyFactory(HessianProxyFactory proxyFactory) {
this.proxyFactory = (proxyFactory != null ? proxyFactory : new HessianProxyFactory());
}
/**
* Specify the Hessian SerializerFactory to use.
* <p>This will typically be passed in as an inner bean definition
* of type {@code com.caucho.hessian.io.SerializerFactory},
* with custom bean property values applied.
*/
public void setSerializerFactory(SerializerFactory serializerFactory) {
this.proxyFactory.setSerializerFactory(serializerFactory);
}
/**
* Set whether to send the Java collection type for each serialized
* collection. Default is "true".
*/
public void setSendCollectionType(boolean sendCollectionType) {
this.proxyFactory.getSerializerFactory().setSendCollectionType(sendCollectionType);
}
/**
* Set whether to allow non-serializable types as Hessian arguments
* and return values. Default is "true".
*/
public void setAllowNonSerializable(boolean allowNonSerializable) {
this.proxyFactory.getSerializerFactory().setAllowNonSerializable(allowNonSerializable);
}
/**
* Set whether overloaded methods should be enabled for remote invocations.
* Default is "false".
* @see com.caucho.hessian.client.HessianProxyFactory#setOverloadEnabled
*/
public void setOverloadEnabled(boolean overloadEnabled) {
this.proxyFactory.setOverloadEnabled(overloadEnabled);
}
/**
* Set the username that this factory should use to access the remote service.
* Default is none.
* <p>The username will be sent by Hessian via HTTP Basic Authentication.
* @see com.caucho.hessian.client.HessianProxyFactory#setUser
*/
public void setUsername(String username) {
this.proxyFactory.setUser(username);
}
/**
* Set the password that this factory should use to access the remote service.
* Default is none.
* <p>The password will be sent by Hessian via HTTP Basic Authentication.
* @see com.caucho.hessian.client.HessianProxyFactory#setPassword
*/
public void setPassword(String password) {
this.proxyFactory.setPassword(password);
}
/**
* Set whether Hessian's debug mode should be enabled.
* Default is "false".
* @see com.caucho.hessian.client.HessianProxyFactory#setDebug
*/
public void setDebug(boolean debug) {
this.proxyFactory.setDebug(debug);
}
/**
* Set whether to use a chunked post for sending a Hessian request.
* @see com.caucho.hessian.client.HessianProxyFactory#setChunkedPost
*/
public void setChunkedPost(boolean chunkedPost) {
this.proxyFactory.setChunkedPost(chunkedPost);
}
/**
* Specify a custom HessianConnectionFactory to use for the Hessian client.
*/
public void setConnectionFactory(HessianConnectionFactory connectionFactory) {
this.proxyFactory.setConnectionFactory(connectionFactory);
}
/**
* Set the socket connect timeout to use for the Hessian client.
* @see com.caucho.hessian.client.HessianProxyFactory#setConnectTimeout
*/
public void setConnectTimeout(long timeout) {
this.proxyFactory.setConnectTimeout(timeout);
}
/**
* Set the timeout to use when waiting for a reply from the Hessian service.
* @see com.caucho.hessian.client.HessianProxyFactory#setReadTimeout
*/
public void setReadTimeout(long timeout) {
this.proxyFactory.setReadTimeout(timeout);
}
/**
* Set whether version 2 of the Hessian protocol should be used for
* parsing requests and replies. Default is "false".
* @see com.caucho.hessian.client.HessianProxyFactory#setHessian2Request
*/
public void setHessian2(boolean hessian2) {
this.proxyFactory.setHessian2Request(hessian2);
this.proxyFactory.setHessian2Reply(hessian2);
}
/**
* Set whether version 2 of the Hessian protocol should be used for
* parsing requests. Default is "false".
* @see com.caucho.hessian.client.HessianProxyFactory#setHessian2Request
*/
public void setHessian2Request(boolean hessian2) {
this.proxyFactory.setHessian2Request(hessian2);
}
/**
* Set whether version 2 of the Hessian protocol should be used for
* parsing replies. Default is "false".
* @see com.caucho.hessian.client.HessianProxyFactory#setHessian2Reply
*/
public void setHessian2Reply(boolean hessian2) {
this.proxyFactory.setHessian2Reply(hessian2);
}
@Override
public void afterPropertiesSet() {
super.afterPropertiesSet();
prepare();
}
/**
* Initialize the Hessian proxy for this interceptor.
* @throws RemoteLookupFailureException if the service URL is invalid
*/
public void prepare() throws RemoteLookupFailureException {
try {
this.hessianProxy = createHessianProxy(this.proxyFactory);
}
catch (MalformedURLException ex) {
throw new RemoteLookupFailureException("Service URL [" + getServiceUrl() + "] is invalid", ex);
}
}
/**
* Create the Hessian proxy that is wrapped by this interceptor.
* @param proxyFactory the proxy factory to use
* @return the Hessian proxy
* @throws MalformedURLException if thrown by the proxy factory
* @see com.caucho.hessian.client.HessianProxyFactory#create
*/
protected Object createHessianProxy(HessianProxyFactory proxyFactory) throws MalformedURLException {
Assert.notNull(getServiceInterface(), "'serviceInterface' is required");
return proxyFactory.create(getServiceInterface(), getServiceUrl(), getBeanClassLoader());
}
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
if (this.hessianProxy == null) {
throw new IllegalStateException("HessianClientInterceptor is not properly initialized - " +
"invoke 'prepare' before attempting any operations");
}
ClassLoader originalClassLoader = overrideThreadContextClassLoader();
try {
return invocation.getMethod().invoke(this.hessianProxy, invocation.getArguments());
}
catch (InvocationTargetException ex) {
Throwable targetEx = ex.getTargetException();
// Hessian 4.0 check: another layer of InvocationTargetException.
if (targetEx instanceof InvocationTargetException) {
targetEx = ((InvocationTargetException) targetEx).getTargetException();
}
if (targetEx instanceof HessianConnectionException) {
throw convertHessianAccessException(targetEx);
}
else if (targetEx instanceof HessianException || targetEx instanceof HessianRuntimeException) {
Throwable cause = targetEx.getCause();
throw convertHessianAccessException(cause != null ? cause : targetEx);
}
else if (targetEx instanceof UndeclaredThrowableException) {
UndeclaredThrowableException utex = (UndeclaredThrowableException) targetEx;
throw convertHessianAccessException(utex.getUndeclaredThrowable());
}
else {
throw targetEx;
}
}
catch (Throwable ex) {
throw new RemoteProxyFailureException(
"Failed to invoke Hessian proxy for remote service [" + getServiceUrl() + "]", ex);
}
finally {
resetThreadContextClassLoader(originalClassLoader);
}
}
/**
* Convert the given Hessian access exception to an appropriate
* Spring RemoteAccessException.
* @param ex the exception to convert
* @return the RemoteAccessException to throw
*/
protected RemoteAccessException convertHessianAccessException(Throwable ex) {
if (ex instanceof HessianConnectionException || ex instanceof ConnectException) {
return new RemoteConnectFailureException(
"Cannot connect to Hessian remote service at [" + getServiceUrl() + "]", ex);
}
else {
return new RemoteAccessException(
"Cannot access Hessian remote service at [" + getServiceUrl() + "]", ex);
}
}
}

247
fine-spring/src/main/java/com/fr/third/springframework/remoting/caucho/HessianExporter.java

@ -1,247 +0,0 @@
/*
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fr.third.springframework.remoting.caucho;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import com.caucho.hessian.io.AbstractHessianInput;
import com.caucho.hessian.io.AbstractHessianOutput;
import com.caucho.hessian.io.Hessian2Input;
import com.caucho.hessian.io.Hessian2Output;
import com.caucho.hessian.io.HessianDebugInputStream;
import com.caucho.hessian.io.HessianDebugOutputStream;
import com.caucho.hessian.io.HessianInput;
import com.caucho.hessian.io.HessianOutput;
import com.caucho.hessian.io.HessianRemoteResolver;
import com.caucho.hessian.io.SerializerFactory;
import com.caucho.hessian.server.HessianSkeleton;
import org.apache.commons.logging.Log;
import com.fr.third.springframework.beans.factory.InitializingBean;
import com.fr.third.springframework.remoting.support.RemoteExporter;
import com.fr.third.springframework.util.Assert;
import com.fr.third.springframework.util.CommonsLogWriter;
/**
* General stream-based protocol exporter for a Hessian endpoint.
*
* <p>Hessian is a slim, binary RPC protocol.
* For information on Hessian, see the
* <a href="http://hessian.caucho.com">Hessian website</a>.
* <b>Note: As of Spring 4.0, this exporter requires Hessian 4.0 or above.</b>
*
* @author Juergen Hoeller
* @since 2.5.1
* @see #invoke(java.io.InputStream, java.io.OutputStream)
* @see HessianServiceExporter
* @see SimpleHessianServiceExporter
*/
public class HessianExporter extends RemoteExporter implements InitializingBean {
public static final String CONTENT_TYPE_HESSIAN = "application/x-hessian";
private SerializerFactory serializerFactory = new SerializerFactory();
private HessianRemoteResolver remoteResolver;
private Log debugLogger;
private HessianSkeleton skeleton;
/**
* Specify the Hessian SerializerFactory to use.
* <p>This will typically be passed in as an inner bean definition
* of type {@code com.caucho.hessian.io.SerializerFactory},
* with custom bean property values applied.
*/
public void setSerializerFactory(SerializerFactory serializerFactory) {
this.serializerFactory = (serializerFactory != null ? serializerFactory : new SerializerFactory());
}
/**
* Set whether to send the Java collection type for each serialized
* collection. Default is "true".
*/
public void setSendCollectionType(boolean sendCollectionType) {
this.serializerFactory.setSendCollectionType(sendCollectionType);
}
/**
* Set whether to allow non-serializable types as Hessian arguments
* and return values. Default is "true".
*/
public void setAllowNonSerializable(boolean allowNonSerializable) {
this.serializerFactory.setAllowNonSerializable(allowNonSerializable);
}
/**
* Specify a custom HessianRemoteResolver to use for resolving remote
* object references.
*/
public void setRemoteResolver(HessianRemoteResolver remoteResolver) {
this.remoteResolver = remoteResolver;
}
/**
* Set whether Hessian's debug mode should be enabled, logging to
* this exporter's Commons Logging log. Default is "false".
* @see com.caucho.hessian.client.HessianProxyFactory#setDebug
*/
public void setDebug(boolean debug) {
this.debugLogger = (debug ? logger : null);
}
@Override
public void afterPropertiesSet() {
prepare();
}
/**
* Initialize this exporter.
*/
public void prepare() {
checkService();
checkServiceInterface();
this.skeleton = new HessianSkeleton(getProxyForService(), getServiceInterface());
}
/**
* Perform an invocation on the exported object.
* @param inputStream the request stream
* @param outputStream the response stream
* @throws Throwable if invocation failed
*/
public void invoke(InputStream inputStream, OutputStream outputStream) throws Throwable {
Assert.notNull(this.skeleton, "Hessian exporter has not been initialized");
doInvoke(this.skeleton, inputStream, outputStream);
}
/**
* Actually invoke the skeleton with the given streams.
* @param skeleton the skeleton to invoke
* @param inputStream the request stream
* @param outputStream the response stream
* @throws Throwable if invocation failed
*/
protected void doInvoke(HessianSkeleton skeleton, InputStream inputStream, OutputStream outputStream)
throws Throwable {
ClassLoader originalClassLoader = overrideThreadContextClassLoader();
try {
InputStream isToUse = inputStream;
OutputStream osToUse = outputStream;
if (this.debugLogger != null && this.debugLogger.isDebugEnabled()) {
PrintWriter debugWriter = new PrintWriter(new CommonsLogWriter(this.debugLogger));
@SuppressWarnings("resource")
HessianDebugInputStream dis = new HessianDebugInputStream(inputStream, debugWriter);
@SuppressWarnings("resource")
HessianDebugOutputStream dos = new HessianDebugOutputStream(outputStream, debugWriter);
dis.startTop2();
dos.startTop2();
isToUse = dis;
osToUse = dos;
}
if (!isToUse.markSupported()) {
isToUse = new BufferedInputStream(isToUse);
isToUse.mark(1);
}
int code = isToUse.read();
int major;
int minor;
AbstractHessianInput in;
AbstractHessianOutput out;
if (code == 'H') {
// Hessian 2.0 stream
major = isToUse.read();
minor = isToUse.read();
if (major != 0x02) {
throw new IOException("Version " + major + '.' + minor + " is not understood");
}
in = new Hessian2Input(isToUse);
out = new Hessian2Output(osToUse);
in.readCall();
}
else if (code == 'C') {
// Hessian 2.0 call... for some reason not handled in HessianServlet!
isToUse.reset();
in = new Hessian2Input(isToUse);
out = new Hessian2Output(osToUse);
in.readCall();
}
else if (code == 'c') {
// Hessian 1.0 call
major = isToUse.read();
minor = isToUse.read();
in = new HessianInput(isToUse);
if (major >= 2) {
out = new Hessian2Output(osToUse);
}
else {
out = new HessianOutput(osToUse);
}
}
else {
throw new IOException("Expected 'H'/'C' (Hessian 2.0) or 'c' (Hessian 1.0) in hessian input at " + code);
}
if (this.serializerFactory != null) {
in.setSerializerFactory(this.serializerFactory);
out.setSerializerFactory(this.serializerFactory);
}
if (this.remoteResolver != null) {
in.setRemoteResolver(this.remoteResolver);
}
try {
skeleton.invoke(in, out);
}
finally {
try {
in.close();
isToUse.close();
}
catch (IOException ex) {
// ignore
}
try {
out.close();
osToUse.close();
}
catch (IOException ex) {
// ignore
}
}
}
finally {
resetThreadContextClassLoader(originalClassLoader);
}
}
}

70
fine-spring/src/main/java/com/fr/third/springframework/remoting/caucho/HessianProxyFactoryBean.java

@ -1,70 +0,0 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fr.third.springframework.remoting.caucho;
import com.fr.third.springframework.aop.framework.ProxyFactory;
import com.fr.third.springframework.beans.factory.FactoryBean;
/**
* {@link FactoryBean} for Hessian proxies. Exposes the proxied service
* for use as a bean reference, using the specified service interface.
*
* <p>Hessian is a slim, binary RPC protocol.
* For information on Hessian, see the
* <a href="http://hessian.caucho.com">Hessian website</a>
* <b>Note: As of Spring 4.0, this proxy factory requires Hessian 4.0 or above.</b>
*
* <p>The service URL must be an HTTP URL exposing a Hessian service.
* For details, see the {@link HessianClientInterceptor} javadoc.
*
* @author Juergen Hoeller
* @since 13.05.2003
* @see #setServiceInterface
* @see #setServiceUrl
* @see HessianClientInterceptor
* @see HessianServiceExporter
* @see com.fr.third.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean
* @see com.fr.third.springframework.remoting.rmi.RmiProxyFactoryBean
*/
public class HessianProxyFactoryBean extends HessianClientInterceptor implements FactoryBean<Object> {
private Object serviceProxy;
@Override
public void afterPropertiesSet() {
super.afterPropertiesSet();
this.serviceProxy = new ProxyFactory(getServiceInterface(), this).getProxy(getBeanClassLoader());
}
@Override
public Object getObject() {
return this.serviceProxy;
}
@Override
public Class<?> getObjectType() {
return getServiceInterface();
}
@Override
public boolean isSingleton() {
return true;
}
}

73
fine-spring/src/main/java/com/fr/third/springframework/remoting/caucho/HessianServiceExporter.java

@ -1,73 +0,0 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fr.third.springframework.remoting.caucho;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.fr.third.springframework.web.HttpRequestHandler;
import com.fr.third.springframework.web.HttpRequestMethodNotSupportedException;
import com.fr.third.springframework.web.util.NestedServletException;
/**
* Servlet-API-based HTTP request handler that exports the specified service bean
* as Hessian service endpoint, accessible via a Hessian proxy.
*
* <p><b>Note:</b> Spring also provides an alternative version of this exporter,
* for Sun's JRE 1.6 HTTP server: {@link SimpleHessianServiceExporter}.
*
* <p>Hessian is a slim, binary RPC protocol.
* For information on Hessian, see the
* <a href="http://hessian.caucho.com">Hessian website</a>.
* <b>Note: As of Spring 4.0, this exporter requires Hessian 4.0 or above.</b>
*
* <p>Hessian services exported with this class can be accessed by
* any Hessian client, as there isn't any special handling involved.
*
* @author Juergen Hoeller
* @since 13.05.2003
* @see HessianClientInterceptor
* @see HessianProxyFactoryBean
* @see com.fr.third.springframework.remoting.httpinvoker.HttpInvokerServiceExporter
* @see com.fr.third.springframework.remoting.rmi.RmiServiceExporter
*/
public class HessianServiceExporter extends HessianExporter implements HttpRequestHandler {
/**
* Processes the incoming Hessian request and creates a Hessian response.
*/
@Override
public void handleRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
if (!"POST".equals(request.getMethod())) {
throw new HttpRequestMethodNotSupportedException(request.getMethod(),
new String[] {"POST"}, "HessianServiceExporter only supports POST requests");
}
response.setContentType(CONTENT_TYPE_HESSIAN);
try {
invoke(request.getInputStream(), response.getOutputStream());
}
catch (Throwable ex) {
throw new NestedServletException("Hessian skeleton invocation failed", ex);
}
}
}

79
fine-spring/src/main/java/com/fr/third/springframework/remoting/caucho/SimpleBurlapServiceExporter.java

@ -1,79 +0,0 @@
/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fr.third.springframework.remoting.caucho;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.fr.third.springframework.lang.UsesSunHttpServer;
import com.fr.third.springframework.util.FileCopyUtils;
/**
* HTTP request handler that exports the specified service bean as
* Burlap service endpoint, accessible via a Burlap proxy.
* Designed for Sun's JRE 1.6 HTTP server, implementing the
* {@link com.sun.net.httpserver.HttpHandler} interface.
*
* <p>Burlap is a slim, XML-based RPC protocol.
* For information on Burlap, see the
* <a href="https://www.caucho.com/burlap">Burlap website</a>.
* This exporter requires Burlap 3.x.
*
* <p>Note: Burlap services exported with this class can be accessed by
* any Burlap client, as there isn't any special handling involved.
*
* @author Juergen Hoeller
* @since 2.5.1
* @see com.fr.third.springframework.remoting.caucho.BurlapClientInterceptor
* @see com.fr.third.springframework.remoting.caucho.BurlapProxyFactoryBean
* @see SimpleHessianServiceExporter
* @see com.fr.third.springframework.remoting.httpinvoker.SimpleHttpInvokerServiceExporter
* @deprecated as of Spring 4.0, since Burlap hasn't evolved in years
* and is effectively retired (in contrast to its sibling Hessian)
*/
@Deprecated
@UsesSunHttpServer
public class SimpleBurlapServiceExporter extends BurlapExporter implements HttpHandler {
/**
* Processes the incoming Burlap request and creates a Burlap response.
*/
@Override
public void handle(HttpExchange exchange) throws IOException {
if (!"POST".equals(exchange.getRequestMethod())) {
exchange.getResponseHeaders().set("Allow", "POST");
exchange.sendResponseHeaders(405, -1);
return;
}
ByteArrayOutputStream output = new ByteArrayOutputStream(1024);
try {
invoke(exchange.getRequestBody(), output);
}
catch (Throwable ex) {
exchange.sendResponseHeaders(500, -1);
logger.error("Burlap skeleton invocation failed", ex);
}
exchange.sendResponseHeaders(200, output.size());
FileCopyUtils.copy(output.toByteArray(), exchange.getResponseBody());
}
}

77
fine-spring/src/main/java/com/fr/third/springframework/remoting/caucho/SimpleHessianServiceExporter.java

@ -1,77 +0,0 @@
/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fr.third.springframework.remoting.caucho;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.fr.third.springframework.lang.UsesSunHttpServer;
import com.fr.third.springframework.util.FileCopyUtils;
/**
* HTTP request handler that exports the specified service bean as
* Hessian service endpoint, accessible via a Hessian proxy.
* Designed for Sun's JRE 1.6 HTTP server, implementing the
* {@link com.sun.net.httpserver.HttpHandler} interface.
*
* <p>Hessian is a slim, binary RPC protocol.
* For information on Hessian, see the
* <a href="http://hessian.caucho.com">Hessian website</a>.
* <b>Note: As of Spring 4.0, this exporter requires Hessian 4.0 or above.</b>
*
* <p>Hessian services exported with this class can be accessed by
* any Hessian client, as there isn't any special handling involved.
*
* @author Juergen Hoeller
* @since 2.5.1
* @see com.fr.third.springframework.remoting.caucho.HessianClientInterceptor
* @see com.fr.third.springframework.remoting.caucho.HessianProxyFactoryBean
* @see com.fr.third.springframework.remoting.httpinvoker.SimpleHttpInvokerServiceExporter
*/
@UsesSunHttpServer
public class SimpleHessianServiceExporter extends HessianExporter implements HttpHandler {
/**
* Processes the incoming Hessian request and creates a Hessian response.
*/
@Override
public void handle(HttpExchange exchange) throws IOException {
if (!"POST".equals(exchange.getRequestMethod())) {
exchange.getResponseHeaders().set("Allow", "POST");
exchange.sendResponseHeaders(405, -1);
return;
}
ByteArrayOutputStream output = new ByteArrayOutputStream(1024);
try {
invoke(exchange.getRequestBody(), output);
}
catch (Throwable ex) {
exchange.sendResponseHeaders(500, -1);
logger.error("Hessian skeleton invocation failed", ex);
return;
}
exchange.getResponseHeaders().set("Content-Type", CONTENT_TYPE_HESSIAN);
exchange.sendResponseHeaders(200, output.size());
FileCopyUtils.copy(output.toByteArray(), exchange.getResponseBody());
}
}

10
fine-spring/src/main/java/com/fr/third/springframework/remoting/caucho/package-info.java

@ -1,10 +0,0 @@
/**
* This package provides remoting classes for Caucho's Hessian protocol:
* a proxy factory for accessing Hessian services, and an exporter for
* making beans available to Hessian clients.
*
* <p>Hessian is a slim, binary RPC protocol over HTTP.
* For information on Hessian, see the
* <a href="http://hessian.caucho.com">Hessian website</a>
*/
package com.fr.third.springframework.remoting.caucho;

299
fine-spring/src/main/java/com/fr/third/springframework/remoting/httpinvoker/AbstractHttpInvokerRequestExecutor.java

@ -1,299 +0,0 @@
/*
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fr.third.springframework.remoting.httpinvoker;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.rmi.RemoteException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.fr.third.springframework.beans.factory.BeanClassLoaderAware;
import com.fr.third.springframework.remoting.rmi.CodebaseAwareObjectInputStream;
import com.fr.third.springframework.remoting.support.RemoteInvocation;
import com.fr.third.springframework.remoting.support.RemoteInvocationResult;
import com.fr.third.springframework.util.Assert;
import com.fr.third.springframework.util.ClassUtils;
/**
* Abstract base implementation of the HttpInvokerRequestExecutor interface.
*
* <p>Pre-implements serialization of RemoteInvocation objects and
* deserialization of RemoteInvocationResults objects.
*
* @author Juergen Hoeller
* @since 1.1
* @see #doExecuteRequest
*/
public abstract class AbstractHttpInvokerRequestExecutor implements HttpInvokerRequestExecutor, BeanClassLoaderAware {
/**
* Default content type: "application/x-java-serialized-object"
*/
public static final String CONTENT_TYPE_SERIALIZED_OBJECT = "application/x-java-serialized-object";
private static final int SERIALIZED_INVOCATION_BYTE_ARRAY_INITIAL_SIZE = 1024;
protected static final String HTTP_METHOD_POST = "POST";
protected static final String HTTP_HEADER_ACCEPT_LANGUAGE = "Accept-Language";
protected static final String HTTP_HEADER_ACCEPT_ENCODING = "Accept-Encoding";
protected static final String HTTP_HEADER_CONTENT_ENCODING = "Content-Encoding";
protected static final String HTTP_HEADER_CONTENT_TYPE = "Content-Type";
protected static final String HTTP_HEADER_CONTENT_LENGTH = "Content-Length";
protected static final String ENCODING_GZIP = "gzip";
protected final Log logger = LogFactory.getLog(getClass());
private String contentType = CONTENT_TYPE_SERIALIZED_OBJECT;
private boolean acceptGzipEncoding = true;
private ClassLoader beanClassLoader;
/**
* Specify the content type to use for sending HTTP invoker requests.
* <p>Default is "application/x-java-serialized-object".
*/
public void setContentType(String contentType) {
Assert.notNull(contentType, "'contentType' must not be null");
this.contentType = contentType;
}
/**
* Return the content type to use for sending HTTP invoker requests.
*/
public String getContentType() {
return this.contentType;
}
/**
* Set whether to accept GZIP encoding, that is, whether to
* send the HTTP "Accept-Encoding" header with "gzip" as value.
* <p>Default is "true". Turn this flag off if you do not want
* GZIP response compression even if enabled on the HTTP server.
*/
public void setAcceptGzipEncoding(boolean acceptGzipEncoding) {
this.acceptGzipEncoding = acceptGzipEncoding;
}
/**
* Return whether to accept GZIP encoding, that is, whether to
* send the HTTP "Accept-Encoding" header with "gzip" as value.
*/
public boolean isAcceptGzipEncoding() {
return this.acceptGzipEncoding;
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.beanClassLoader = classLoader;
}
/**
* Return the bean ClassLoader that this executor is supposed to use.
*/
protected ClassLoader getBeanClassLoader() {
return this.beanClassLoader;
}
@Override
public final RemoteInvocationResult executeRequest(
HttpInvokerClientConfiguration config, RemoteInvocation invocation) throws Exception {
ByteArrayOutputStream baos = getByteArrayOutputStream(invocation);
if (logger.isDebugEnabled()) {
logger.debug("Sending HTTP invoker request for service at [" + config.getServiceUrl() +
"], with size " + baos.size());
}
return doExecuteRequest(config, baos);
}
/**
* Serialize the given RemoteInvocation into a ByteArrayOutputStream.
* @param invocation the RemoteInvocation object
* @return a ByteArrayOutputStream with the serialized RemoteInvocation
* @throws IOException if thrown by I/O methods
*/
protected ByteArrayOutputStream getByteArrayOutputStream(RemoteInvocation invocation) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream(SERIALIZED_INVOCATION_BYTE_ARRAY_INITIAL_SIZE);
writeRemoteInvocation(invocation, baos);
return baos;
}
/**
* Serialize the given RemoteInvocation to the given OutputStream.
* <p>The default implementation gives {@code decorateOutputStream} a chance
* to decorate the stream first (for example, for custom encryption or compression).
* Creates an {@code ObjectOutputStream} for the final stream and calls
* {@code doWriteRemoteInvocation} to actually write the object.
* <p>Can be overridden for custom serialization of the invocation.
* @param invocation the RemoteInvocation object
* @param os the OutputStream to write to
* @throws IOException if thrown by I/O methods
* @see #decorateOutputStream
* @see #doWriteRemoteInvocation
*/
protected void writeRemoteInvocation(RemoteInvocation invocation, OutputStream os) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(decorateOutputStream(os));
try {
doWriteRemoteInvocation(invocation, oos);
}
finally {
oos.close();
}
}
/**
* Return the OutputStream to use for writing remote invocations,
* potentially decorating the given original OutputStream.
* <p>The default implementation returns the given stream as-is.
* Can be overridden, for example, for custom encryption or compression.
* @param os the original OutputStream
* @return the potentially decorated OutputStream
*/
protected OutputStream decorateOutputStream(OutputStream os) throws IOException {
return os;
}
/**
* Perform the actual writing of the given invocation object to the
* given ObjectOutputStream.
* <p>The default implementation simply calls {@code writeObject}.
* Can be overridden for serialization of a custom wrapper object rather
* than the plain invocation, for example an encryption-aware holder.
* @param invocation the RemoteInvocation object
* @param oos the ObjectOutputStream to write to
* @throws IOException if thrown by I/O methods
* @see java.io.ObjectOutputStream#writeObject
*/
protected void doWriteRemoteInvocation(RemoteInvocation invocation, ObjectOutputStream oos) throws IOException {
oos.writeObject(invocation);
}
/**
* Execute a request to send the given serialized remote invocation.
* <p>Implementations will usually call {@code readRemoteInvocationResult}
* to deserialize a returned RemoteInvocationResult object.
* @param config the HTTP invoker configuration that specifies the
* target service
* @param baos the ByteArrayOutputStream that contains the serialized
* RemoteInvocation object
* @return the RemoteInvocationResult object
* @throws IOException if thrown by I/O operations
* @throws ClassNotFoundException if thrown during deserialization
* @throws Exception in case of general errors
* @see #readRemoteInvocationResult(java.io.InputStream, String)
*/
protected abstract RemoteInvocationResult doExecuteRequest(
HttpInvokerClientConfiguration config, ByteArrayOutputStream baos)
throws Exception;
/**
* Deserialize a RemoteInvocationResult object from the given InputStream.
* <p>Gives {@code decorateInputStream} a chance to decorate the stream
* first (for example, for custom encryption or compression). Creates an
* {@code ObjectInputStream} via {@code createObjectInputStream} and
* calls {@code doReadRemoteInvocationResult} to actually read the object.
* <p>Can be overridden for custom serialization of the invocation.
* @param is the InputStream to read from
* @param codebaseUrl the codebase URL to load classes from if not found locally
* @return the RemoteInvocationResult object
* @throws IOException if thrown by I/O methods
* @throws ClassNotFoundException if thrown during deserialization
* @see #decorateInputStream
* @see #createObjectInputStream
* @see #doReadRemoteInvocationResult
*/
protected RemoteInvocationResult readRemoteInvocationResult(InputStream is, String codebaseUrl)
throws IOException, ClassNotFoundException {
ObjectInputStream ois = createObjectInputStream(decorateInputStream(is), codebaseUrl);
try {
return doReadRemoteInvocationResult(ois);
}
finally {
ois.close();
}
}
/**
* Return the InputStream to use for reading remote invocation results,
* potentially decorating the given original InputStream.
* <p>The default implementation returns the given stream as-is.
* Can be overridden, for example, for custom encryption or compression.
* @param is the original InputStream
* @return the potentially decorated InputStream
*/
protected InputStream decorateInputStream(InputStream is) throws IOException {
return is;
}
/**
* Create an ObjectInputStream for the given InputStream and codebase.
* The default implementation creates a CodebaseAwareObjectInputStream.
* @param is the InputStream to read from
* @param codebaseUrl the codebase URL to load classes from if not found locally
* (can be {@code null})
* @return the new ObjectInputStream instance to use
* @throws IOException if creation of the ObjectInputStream failed
* @see com.fr.third.springframework.remoting.rmi.CodebaseAwareObjectInputStream
*/
protected ObjectInputStream createObjectInputStream(InputStream is, String codebaseUrl) throws IOException {
return new CodebaseAwareObjectInputStream(is, getBeanClassLoader(), codebaseUrl);
}
/**
* Perform the actual reading of an invocation object from the
* given ObjectInputStream.
* <p>The default implementation simply calls {@code readObject}.
* Can be overridden for deserialization of a custom wrapper object rather
* than the plain invocation, for example an encryption-aware holder.
* @param ois the ObjectInputStream to read from
* @return the RemoteInvocationResult object
* @throws IOException if thrown by I/O methods
* @throws ClassNotFoundException if the class name of a serialized object
* couldn't get resolved
* @see java.io.ObjectOutputStream#writeObject
*/
protected RemoteInvocationResult doReadRemoteInvocationResult(ObjectInputStream ois)
throws IOException, ClassNotFoundException {
Object obj = ois.readObject();
if (!(obj instanceof RemoteInvocationResult)) {
throw new RemoteException("Deserialized object needs to be assignable to type [" +
RemoteInvocationResult.class.getName() + "]: " + ClassUtils.getDescriptiveType(obj));
}
return (RemoteInvocationResult) obj;
}
}

418
fine-spring/src/main/java/com/fr/third/springframework/remoting/httpinvoker/HttpComponentsHttpInvokerRequestExecutor.java

@ -1,418 +0,0 @@
/*
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fr.third.springframework.remoting.httpinvoker;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Locale;
import java.util.zip.GZIPInputStream;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.NoHttpResponseException;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.Configurable;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import com.fr.third.springframework.context.i18n.LocaleContext;
import com.fr.third.springframework.context.i18n.LocaleContextHolder;
import com.fr.third.springframework.remoting.support.RemoteInvocationResult;
import com.fr.third.springframework.util.Assert;
import com.fr.third.springframework.util.ClassUtils;
import com.fr.third.springframework.util.StringUtils;
/**
* {@link com.fr.third.springframework.remoting.httpinvoker.HttpInvokerRequestExecutor} implementation that uses
* <a href="https://hc.apache.org/httpcomponents-client-ga/httpclient/">Apache HttpComponents HttpClient</a>
* to execute POST requests.
*
* <p>Allows to use a pre-configured {@link org.apache.http.client.HttpClient}
* instance, potentially with authentication, HTTP connection pooling, etc.
* Also designed for easy subclassing, providing specific template methods.
*
* <p>As of Spring 4.1, this request executor requires Apache HttpComponents 4.3 or higher.
*
* @author Juergen Hoeller
* @author Stephane Nicoll
* @since 3.1
* @see com.fr.third.springframework.remoting.httpinvoker.SimpleHttpInvokerRequestExecutor
*/
public class HttpComponentsHttpInvokerRequestExecutor extends AbstractHttpInvokerRequestExecutor {
private static final int DEFAULT_MAX_TOTAL_CONNECTIONS = 100;
private static final int DEFAULT_MAX_CONNECTIONS_PER_ROUTE = 5;
private static final int DEFAULT_READ_TIMEOUT_MILLISECONDS = (60 * 1000);
private static Class<?> abstractHttpClientClass;
static {
try {
// Looking for AbstractHttpClient class (deprecated as of HttpComponents 4.3)
abstractHttpClientClass = ClassUtils.forName("org.apache.http.impl.client.AbstractHttpClient",
HttpComponentsHttpInvokerRequestExecutor.class.getClassLoader());
}
catch (ClassNotFoundException ex) {
// Probably removed from HttpComponents in the meantime...
}
}
private HttpClient httpClient;
private RequestConfig requestConfig;
/**
* Create a new instance of the HttpComponentsHttpInvokerRequestExecutor with a default
* {@link HttpClient} that uses a default {@code org.apache.http.impl.conn.PoolingClientConnectionManager}.
*/
public HttpComponentsHttpInvokerRequestExecutor() {
this(createDefaultHttpClient(), RequestConfig.custom()
.setSocketTimeout(DEFAULT_READ_TIMEOUT_MILLISECONDS).build());
}
/**
* Create a new instance of the HttpComponentsClientHttpRequestFactory
* with the given {@link HttpClient} instance.
* @param httpClient the HttpClient instance to use for this request executor
*/
public HttpComponentsHttpInvokerRequestExecutor(HttpClient httpClient) {
this(httpClient, null);
}
private HttpComponentsHttpInvokerRequestExecutor(HttpClient httpClient, RequestConfig requestConfig) {
this.httpClient = httpClient;
this.requestConfig = requestConfig;
}
private static HttpClient createDefaultHttpClient() {
Registry<ConnectionSocketFactory> schemeRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", SSLConnectionSocketFactory.getSocketFactory())
.build();
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(schemeRegistry);
connectionManager.setMaxTotal(DEFAULT_MAX_TOTAL_CONNECTIONS);
connectionManager.setDefaultMaxPerRoute(DEFAULT_MAX_CONNECTIONS_PER_ROUTE);
return HttpClientBuilder.create().setConnectionManager(connectionManager).build();
}
/**
* Set the {@link HttpClient} instance to use for this request executor.
*/
public void setHttpClient(HttpClient httpClient) {
this.httpClient = httpClient;
}
/**
* Return the {@link HttpClient} instance that this request executor uses.
*/
public HttpClient getHttpClient() {
return this.httpClient;
}
/**
* Set the connection timeout for the underlying HttpClient.
* A timeout value of 0 specifies an infinite timeout.
* <p>Additional properties can be configured by specifying a
* {@link RequestConfig} instance on a custom {@link HttpClient}.
* @param timeout the timeout value in milliseconds
* @see RequestConfig#getConnectTimeout()
*/
public void setConnectTimeout(int timeout) {
Assert.isTrue(timeout >= 0, "Timeout must be a non-negative value");
this.requestConfig = cloneRequestConfig().setConnectTimeout(timeout).build();
setLegacyConnectionTimeout(getHttpClient(), timeout);
}
/**
* Apply the specified connection timeout to deprecated {@link HttpClient}
* implementations.
* <p>As of HttpClient 4.3, default parameters have to be exposed through a
* {@link RequestConfig} instance instead of setting the parameters on the
* client. Unfortunately, this behavior is not backward-compatible and older
* {@link HttpClient} implementations will ignore the {@link RequestConfig}
* object set in the context.
* <p>If the specified client is an older implementation, we set the custom
* connection timeout through the deprecated API. Otherwise, we just return
* as it is set through {@link RequestConfig} with newer clients.
* @param client the client to configure
* @param timeout the custom connection timeout
*/
@SuppressWarnings("deprecation")
private void setLegacyConnectionTimeout(HttpClient client, int timeout) {
if (abstractHttpClientClass != null && abstractHttpClientClass.isInstance(client)) {
client.getParams().setIntParameter(org.apache.http.params.CoreConnectionPNames.CONNECTION_TIMEOUT, timeout);
}
}
/**
* Set the timeout in milliseconds used when requesting a connection from the connection
* manager using the underlying HttpClient.
* A timeout value of 0 specifies an infinite timeout.
* <p>Additional properties can be configured by specifying a
* {@link RequestConfig} instance on a custom {@link HttpClient}.
* @param connectionRequestTimeout the timeout value to request a connection in milliseconds
* @see RequestConfig#getConnectionRequestTimeout()
*/
public void setConnectionRequestTimeout(int connectionRequestTimeout) {
this.requestConfig = cloneRequestConfig().setConnectionRequestTimeout(connectionRequestTimeout).build();
}
/**
* Set the socket read timeout for the underlying HttpClient.
* A timeout value of 0 specifies an infinite timeout.
* <p>Additional properties can be configured by specifying a
* {@link RequestConfig} instance on a custom {@link HttpClient}.
* @param timeout the timeout value in milliseconds
* @see #DEFAULT_READ_TIMEOUT_MILLISECONDS
* @see RequestConfig#getSocketTimeout()
*/
public void setReadTimeout(int timeout) {
Assert.isTrue(timeout >= 0, "Timeout must be a non-negative value");
this.requestConfig = cloneRequestConfig().setSocketTimeout(timeout).build();
setLegacySocketTimeout(getHttpClient(), timeout);
}
/**
* Apply the specified socket timeout to deprecated {@link HttpClient}
* implementations. See {@link #setLegacyConnectionTimeout}.
* @param client the client to configure
* @param timeout the custom socket timeout
* @see #setLegacyConnectionTimeout
*/
@SuppressWarnings("deprecation")
private void setLegacySocketTimeout(HttpClient client, int timeout) {
if (abstractHttpClientClass != null && abstractHttpClientClass.isInstance(client)) {
client.getParams().setIntParameter(org.apache.http.params.CoreConnectionPNames.SO_TIMEOUT, timeout);
}
}
private RequestConfig.Builder cloneRequestConfig() {
return (this.requestConfig != null ? RequestConfig.copy(this.requestConfig) : RequestConfig.custom());
}
/**
* Execute the given request through the HttpClient.
* <p>This method implements the basic processing workflow:
* The actual work happens in this class's template methods.
* @see #createHttpPost
* @see #setRequestBody
* @see #executeHttpPost
* @see #validateResponse
* @see #getResponseBody
*/
@Override
protected RemoteInvocationResult doExecuteRequest(
HttpInvokerClientConfiguration config, ByteArrayOutputStream baos)
throws IOException, ClassNotFoundException {
HttpPost postMethod = createHttpPost(config);
setRequestBody(config, postMethod, baos);
try {
HttpResponse response = executeHttpPost(config, getHttpClient(), postMethod);
validateResponse(config, response);
InputStream responseBody = getResponseBody(config, response);
return readRemoteInvocationResult(responseBody, config.getCodebaseUrl());
}
finally {
postMethod.releaseConnection();
}
}
/**
* Create a HttpPost for the given configuration.
* <p>The default implementation creates a standard HttpPost with
* "application/x-java-serialized-object" as "Content-Type" header.
* @param config the HTTP invoker configuration that specifies the
* target service
* @return the HttpPost instance
* @throws java.io.IOException if thrown by I/O methods
*/
protected HttpPost createHttpPost(HttpInvokerClientConfiguration config) throws IOException {
HttpPost httpPost = new HttpPost(config.getServiceUrl());
RequestConfig requestConfig = createRequestConfig(config);
if (requestConfig != null) {
httpPost.setConfig(requestConfig);
}
LocaleContext localeContext = LocaleContextHolder.getLocaleContext();
if (localeContext != null) {
Locale locale = localeContext.getLocale();
if (locale != null) {
httpPost.addHeader(HTTP_HEADER_ACCEPT_LANGUAGE, StringUtils.toLanguageTag(locale));
}
}
if (isAcceptGzipEncoding()) {
httpPost.addHeader(HTTP_HEADER_ACCEPT_ENCODING, ENCODING_GZIP);
}
return httpPost;
}
/**
* Create a {@link RequestConfig} for the given configuration. Can return {@code null}
* to indicate that no custom request config should be set and the defaults of the
* {@link HttpClient} should be used.
* <p>The default implementation tries to merge the defaults of the client with the
* local customizations of the instance, if any.
* @param config the HTTP invoker configuration that specifies the
* target service
* @return the RequestConfig to use
*/
protected RequestConfig createRequestConfig(HttpInvokerClientConfiguration config) {
HttpClient client = getHttpClient();
if (client instanceof Configurable) {
RequestConfig clientRequestConfig = ((Configurable) client).getConfig();
return mergeRequestConfig(clientRequestConfig);
}
return this.requestConfig;
}
private RequestConfig mergeRequestConfig(RequestConfig defaultRequestConfig) {
if (this.requestConfig == null) { // nothing to merge
return defaultRequestConfig;
}
RequestConfig.Builder builder = RequestConfig.copy(defaultRequestConfig);
int connectTimeout = this.requestConfig.getConnectTimeout();
if (connectTimeout >= 0) {
builder.setConnectTimeout(connectTimeout);
}
int connectionRequestTimeout = this.requestConfig.getConnectionRequestTimeout();
if (connectionRequestTimeout >= 0) {
builder.setConnectionRequestTimeout(connectionRequestTimeout);
}
int socketTimeout = this.requestConfig.getSocketTimeout();
if (socketTimeout >= 0) {
builder.setSocketTimeout(socketTimeout);
}
return builder.build();
}
/**
* Set the given serialized remote invocation as request body.
* <p>The default implementation simply sets the serialized invocation as the
* HttpPost's request body. This can be overridden, for example, to write a
* specific encoding and to potentially set appropriate HTTP request headers.
* @param config the HTTP invoker configuration that specifies the target service
* @param httpPost the HttpPost to set the request body on
* @param baos the ByteArrayOutputStream that contains the serialized
* RemoteInvocation object
* @throws java.io.IOException if thrown by I/O methods
*/
protected void setRequestBody(
HttpInvokerClientConfiguration config, HttpPost httpPost, ByteArrayOutputStream baos)
throws IOException {
ByteArrayEntity entity = new ByteArrayEntity(baos.toByteArray());
entity.setContentType(getContentType());
httpPost.setEntity(entity);
}
/**
* Execute the given HttpPost instance.
* @param config the HTTP invoker configuration that specifies the target service
* @param httpClient the HttpClient to execute on
* @param httpPost the HttpPost to execute
* @return the resulting HttpResponse
* @throws java.io.IOException if thrown by I/O methods
*/
protected HttpResponse executeHttpPost(
HttpInvokerClientConfiguration config, HttpClient httpClient, HttpPost httpPost)
throws IOException {
return httpClient.execute(httpPost);
}
/**
* Validate the given response as contained in the HttpPost object,
* throwing an exception if it does not correspond to a successful HTTP response.
* <p>Default implementation rejects any HTTP status code beyond 2xx, to avoid
* parsing the response body and trying to deserialize from a corrupted stream.
* @param config the HTTP invoker configuration that specifies the target service
* @param response the resulting HttpResponse to validate
* @throws java.io.IOException if validation failed
*/
protected void validateResponse(HttpInvokerClientConfiguration config, HttpResponse response)
throws IOException {
StatusLine status = response.getStatusLine();
if (status.getStatusCode() >= 300) {
throw new NoHttpResponseException(
"Did not receive successful HTTP response: status code = " + status.getStatusCode() +
", status message = [" + status.getReasonPhrase() + "]");
}
}
/**
* Extract the response body from the given executed remote invocation request.
* <p>The default implementation simply fetches the HttpPost's response body stream.
* If the response is recognized as GZIP response, the InputStream will get wrapped
* in a GZIPInputStream.
* @param config the HTTP invoker configuration that specifies the target service
* @param httpResponse the resulting HttpResponse to read the response body from
* @return an InputStream for the response body
* @throws java.io.IOException if thrown by I/O methods
* @see #isGzipResponse
* @see java.util.zip.GZIPInputStream
*/
protected InputStream getResponseBody(HttpInvokerClientConfiguration config, HttpResponse httpResponse)
throws IOException {
if (isGzipResponse(httpResponse)) {
return new GZIPInputStream(httpResponse.getEntity().getContent());
}
else {
return httpResponse.getEntity().getContent();
}
}
/**
* Determine whether the given response indicates a GZIP response.
* <p>The default implementation checks whether the HTTP "Content-Encoding"
* header contains "gzip" (in any casing).
* @param httpResponse the resulting HttpResponse to check
* @return whether the given response indicates a GZIP response
*/
protected boolean isGzipResponse(HttpResponse httpResponse) {
Header encodingHeader = httpResponse.getFirstHeader(HTTP_HEADER_CONTENT_ENCODING);
return (encodingHeader != null && encodingHeader.getValue() != null &&
encodingHeader.getValue().toLowerCase().contains(ENCODING_GZIP));
}
}

42
fine-spring/src/main/java/com/fr/third/springframework/remoting/httpinvoker/HttpInvokerClientConfiguration.java

@ -1,42 +0,0 @@
/*
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fr.third.springframework.remoting.httpinvoker;
/**
* Configuration interface for executing HTTP invoker requests.
*
* @author Juergen Hoeller
* @since 1.1
* @see HttpInvokerRequestExecutor
* @see HttpInvokerClientInterceptor
*/
public interface HttpInvokerClientConfiguration {
/**
* Return the HTTP URL of the target service.
*/
String getServiceUrl();
/**
* Return the codebase URL to download classes from if not found locally.
* Can consist of multiple URLs, separated by spaces.
* @return the codebase URL, or {@code null} if none
* @see java.rmi.server.RMIClassLoader
*/
String getCodebaseUrl();
}

233
fine-spring/src/main/java/com/fr/third/springframework/remoting/httpinvoker/HttpInvokerClientInterceptor.java

@ -1,233 +0,0 @@
/*
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fr.third.springframework.remoting.httpinvoker;
import java.io.IOException;
import java.io.InvalidClassException;
import java.net.ConnectException;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import com.fr.third.springframework.aop.support.AopUtils;
import com.fr.third.springframework.remoting.RemoteAccessException;
import com.fr.third.springframework.remoting.RemoteConnectFailureException;
import com.fr.third.springframework.remoting.RemoteInvocationFailureException;
import com.fr.third.springframework.remoting.support.RemoteInvocation;
import com.fr.third.springframework.remoting.support.RemoteInvocationBasedAccessor;
import com.fr.third.springframework.remoting.support.RemoteInvocationResult;
/**
* {@link org.aopalliance.intercept.MethodInterceptor} for accessing an
* HTTP invoker service. The service URL must be an HTTP URL exposing
* an HTTP invoker service.
*
* <p>Serializes remote invocation objects and deserializes remote invocation
* result objects. Uses Java serialization just like RMI, but provides the
* same ease of setup as Caucho's HTTP-based Hessian and Burlap protocols.
*
* <P>HTTP invoker is a very extensible and customizable protocol.
* It supports the RemoteInvocationFactory mechanism, like RMI invoker,
* allowing to include additional invocation attributes (for example,
* a security context). Furthermore, it allows to customize request
* execution via the {@link HttpInvokerRequestExecutor} strategy.
*
* <p>Can use the JDK's {@link java.rmi.server.RMIClassLoader} to load classes
* from a given {@link #setCodebaseUrl codebase}, performing on-demand dynamic
* code download from a remote location. The codebase can consist of multiple
* URLs, separated by spaces. Note that RMIClassLoader requires a SecurityManager
* to be set, analogous to when using dynamic class download with standard RMI!
* (See the RMI documentation for details.)
*
* <p><b>WARNING: Be aware of vulnerabilities due to unsafe Java deserialization:
* Manipulated input streams could lead to unwanted code execution on the server
* during the deserialization step. As a consequence, do not expose HTTP invoker
* endpoints to untrusted clients but rather just between your own services.</b>
* In general, we strongly recommend any other message format (e.g. JSON) instead.
*
* @author Juergen Hoeller
* @since 1.1
* @see #setServiceUrl
* @see #setCodebaseUrl
* @see #setRemoteInvocationFactory
* @see #setHttpInvokerRequestExecutor
* @see HttpInvokerServiceExporter
* @see HttpInvokerProxyFactoryBean
* @see java.rmi.server.RMIClassLoader
*/
public class HttpInvokerClientInterceptor extends RemoteInvocationBasedAccessor
implements MethodInterceptor, HttpInvokerClientConfiguration {
private String codebaseUrl;
private HttpInvokerRequestExecutor httpInvokerRequestExecutor;
/**
* Set the codebase URL to download classes from if not found locally.
* Can consists of multiple URLs, separated by spaces.
* <p>Follows RMI's codebase conventions for dynamic class download.
* In contrast to RMI, where the server determines the URL for class download
* (via the "java.rmi.server.codebase" system property), it's the client
* that determines the codebase URL here. The server will usually be the
* same as for the service URL, just pointing to a different path there.
* @see #setServiceUrl
* @see com.fr.third.springframework.remoting.rmi.CodebaseAwareObjectInputStream
* @see java.rmi.server.RMIClassLoader
*/
public void setCodebaseUrl(String codebaseUrl) {
this.codebaseUrl = codebaseUrl;
}
/**
* Return the codebase URL to download classes from if not found locally.
*/
@Override
public String getCodebaseUrl() {
return this.codebaseUrl;
}
/**
* Set the HttpInvokerRequestExecutor implementation to use for executing
* remote invocations.
* <p>Default is {@link SimpleHttpInvokerRequestExecutor}. Alternatively,
* consider using {@link HttpComponentsHttpInvokerRequestExecutor} for more
* sophisticated needs.
* @see SimpleHttpInvokerRequestExecutor
* @see HttpComponentsHttpInvokerRequestExecutor
*/
public void setHttpInvokerRequestExecutor(HttpInvokerRequestExecutor httpInvokerRequestExecutor) {
this.httpInvokerRequestExecutor = httpInvokerRequestExecutor;
}
/**
* Return the HttpInvokerRequestExecutor used by this remote accessor.
* <p>Creates a default SimpleHttpInvokerRequestExecutor if no executor
* has been initialized already.
*/
public HttpInvokerRequestExecutor getHttpInvokerRequestExecutor() {
if (this.httpInvokerRequestExecutor == null) {
SimpleHttpInvokerRequestExecutor executor = new SimpleHttpInvokerRequestExecutor();
executor.setBeanClassLoader(getBeanClassLoader());
this.httpInvokerRequestExecutor = executor;
}
return this.httpInvokerRequestExecutor;
}
@Override
public void afterPropertiesSet() {
super.afterPropertiesSet();
// Eagerly initialize the default HttpInvokerRequestExecutor, if needed.
getHttpInvokerRequestExecutor();
}
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
if (AopUtils.isToStringMethod(methodInvocation.getMethod())) {
return "HTTP invoker proxy for service URL [" + getServiceUrl() + "]";
}
RemoteInvocation invocation = createRemoteInvocation(methodInvocation);
RemoteInvocationResult result;
try {
result = executeRequest(invocation, methodInvocation);
}
catch (Throwable ex) {
RemoteAccessException rae = convertHttpInvokerAccessException(ex);
throw (rae != null ? rae : ex);
}
try {
return recreateRemoteInvocationResult(result);
}
catch (Throwable ex) {
if (result.hasInvocationTargetException()) {
throw ex;
}
else {
throw new RemoteInvocationFailureException("Invocation of method [" + methodInvocation.getMethod() +
"] failed in HTTP invoker remote service at [" + getServiceUrl() + "]", ex);
}
}
}
/**
* Execute the given remote invocation via the {@link HttpInvokerRequestExecutor}.
* <p>This implementation delegates to {@link #executeRequest(RemoteInvocation)}.
* Can be overridden to react to the specific original MethodInvocation.
* @param invocation the RemoteInvocation to execute
* @param originalInvocation the original MethodInvocation (can e.g. be cast
* to the ProxyMethodInvocation interface for accessing user attributes)
* @return the RemoteInvocationResult object
* @throws Exception in case of errors
*/
protected RemoteInvocationResult executeRequest(
RemoteInvocation invocation, MethodInvocation originalInvocation) throws Exception {
return executeRequest(invocation);
}
/**
* Execute the given remote invocation via the {@link HttpInvokerRequestExecutor}.
* <p>Can be overridden in subclasses to pass a different configuration object
* to the executor. Alternatively, add further configuration properties in a
* subclass of this accessor: By default, the accessor passed itself as
* configuration object to the executor.
* @param invocation the RemoteInvocation to execute
* @return the RemoteInvocationResult object
* @throws IOException if thrown by I/O operations
* @throws ClassNotFoundException if thrown during deserialization
* @throws Exception in case of general errors
* @see #getHttpInvokerRequestExecutor
* @see HttpInvokerClientConfiguration
*/
protected RemoteInvocationResult executeRequest(RemoteInvocation invocation) throws Exception {
return getHttpInvokerRequestExecutor().executeRequest(this, invocation);
}
/**
* Convert the given HTTP invoker access exception to an appropriate
* Spring {@link RemoteAccessException}.
* @param ex the exception to convert
* @return the RemoteAccessException to throw, or {@code null} to have the
* original exception propagated to the caller
*/
protected RemoteAccessException convertHttpInvokerAccessException(Throwable ex) {
if (ex instanceof ConnectException) {
return new RemoteConnectFailureException(
"Could not connect to HTTP invoker remote service at [" + getServiceUrl() + "]", ex);
}
if (ex instanceof ClassNotFoundException || ex instanceof NoClassDefFoundError ||
ex instanceof InvalidClassException) {
return new RemoteAccessException(
"Could not deserialize result from HTTP invoker remote service [" + getServiceUrl() + "]", ex);
}
if (ex instanceof Exception) {
return new RemoteAccessException(
"Could not access HTTP invoker remote service at [" + getServiceUrl() + "]", ex);
}
// For any other Throwable, e.g. OutOfMemoryError: let it get propagated as-is.
return null;
}
}

86
fine-spring/src/main/java/com/fr/third/springframework/remoting/httpinvoker/HttpInvokerProxyFactoryBean.java

@ -1,86 +0,0 @@
/*
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fr.third.springframework.remoting.httpinvoker;
import com.fr.third.springframework.aop.framework.ProxyFactory;
import com.fr.third.springframework.beans.factory.FactoryBean;
/**
* {@link FactoryBean} for HTTP invoker proxies. Exposes the proxied service
* for use as a bean reference, using the specified service interface.
*
* <p>The service URL must be an HTTP URL exposing an HTTP invoker service.
* Optionally, a codebase URL can be specified for on-demand dynamic code download
* from a remote location. For details, see HttpInvokerClientInterceptor docs.
*
* <p>Serializes remote invocation objects and deserializes remote invocation
* result objects. Uses Java serialization just like RMI, but provides the
* same ease of setup as Caucho's HTTP-based Hessian and Burlap protocols.
*
* <p><b>HTTP invoker is the recommended protocol for Java-to-Java remoting.</b>
* It is more powerful and more extensible than Hessian and Burlap, at the
* expense of being tied to Java. Nevertheless, it is as easy to set up as
* Hessian and Burlap, which is its main advantage compared to RMI.
*
* <p><b>WARNING: Be aware of vulnerabilities due to unsafe Java deserialization:
* Manipulated input streams could lead to unwanted code execution on the server
* during the deserialization step. As a consequence, do not expose HTTP invoker
* endpoints to untrusted clients but rather just between your own services.</b>
* In general, we strongly recommend any other message format (e.g. JSON) instead.
*
* @author Juergen Hoeller
* @since 1.1
* @see #setServiceInterface
* @see #setServiceUrl
* @see #setCodebaseUrl
* @see HttpInvokerClientInterceptor
* @see HttpInvokerServiceExporter
* @see com.fr.third.springframework.remoting.rmi.RmiProxyFactoryBean
* @see com.fr.third.springframework.remoting.caucho.HessianProxyFactoryBean
* @see com.fr.third.springframework.remoting.caucho.BurlapProxyFactoryBean
*/
public class HttpInvokerProxyFactoryBean extends HttpInvokerClientInterceptor implements FactoryBean<Object> {
private Object serviceProxy;
@Override
public void afterPropertiesSet() {
super.afterPropertiesSet();
if (getServiceInterface() == null) {
throw new IllegalArgumentException("Property 'serviceInterface' is required");
}
this.serviceProxy = new ProxyFactory(getServiceInterface(), this).getProxy(getBeanClassLoader());
}
@Override
public Object getObject() {
return this.serviceProxy;
}
@Override
public Class<?> getObjectType() {
return getServiceInterface();
}
@Override
public boolean isSingleton() {
return true;
}
}

59
fine-spring/src/main/java/com/fr/third/springframework/remoting/httpinvoker/HttpInvokerRequestExecutor.java

@ -1,59 +0,0 @@
/*
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fr.third.springframework.remoting.httpinvoker;
import java.io.IOException;
import com.fr.third.springframework.remoting.support.RemoteInvocation;
import com.fr.third.springframework.remoting.support.RemoteInvocationResult;
/**
* Strategy interface for actual execution of an HTTP invoker request.
* Used by HttpInvokerClientInterceptor and its subclass
* HttpInvokerProxyFactoryBean.
*
* <p>Two implementations are provided out of the box:
* <ul>
* <li><b>{@code SimpleHttpInvokerRequestExecutor}:</b>
* Uses JDK facilities to execute POST requests, without support
* for HTTP authentication or advanced configuration options.
* <li><b>{@code HttpComponentsHttpInvokerRequestExecutor}:</b>
* Uses Apache's Commons HttpClient to execute POST requests,
* allowing to use a preconfigured HttpClient instance
* (potentially with authentication, HTTP connection pooling, etc).
* </ul>
*
* @author Juergen Hoeller
* @since 1.1
* @see HttpInvokerClientInterceptor#setHttpInvokerRequestExecutor
*/
public interface HttpInvokerRequestExecutor {
/**
* Execute a request to send the given remote invocation.
* @param config the HTTP invoker configuration that specifies the
* target service
* @param invocation the RemoteInvocation to execute
* @return the RemoteInvocationResult object
* @throws IOException if thrown by I/O operations
* @throws ClassNotFoundException if thrown during deserialization
* @throws Exception in case of general errors
*/
RemoteInvocationResult executeRequest(HttpInvokerClientConfiguration config, RemoteInvocation invocation)
throws Exception;
}

225
fine-spring/src/main/java/com/fr/third/springframework/remoting/httpinvoker/HttpInvokerServiceExporter.java

@ -1,225 +0,0 @@
/*
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fr.third.springframework.remoting.httpinvoker;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.fr.third.springframework.remoting.rmi.RemoteInvocationSerializingExporter;
import com.fr.third.springframework.remoting.support.RemoteInvocation;
import com.fr.third.springframework.remoting.support.RemoteInvocationResult;
import com.fr.third.springframework.web.HttpRequestHandler;
import com.fr.third.springframework.web.util.NestedServletException;
/**
* Servlet-API-based HTTP request handler that exports the specified service bean
* as HTTP invoker service endpoint, accessible via an HTTP invoker proxy.
*
* <p><b>Note:</b> Spring also provides an alternative version of this exporter,
* for Sun's JRE 1.6 HTTP server: {@link SimpleHttpInvokerServiceExporter}.
*
* <p>Deserializes remote invocation objects and serializes remote invocation
* result objects. Uses Java serialization just like RMI, but provides the
* same ease of setup as Caucho's HTTP-based Hessian and Burlap protocols.
*
* <p><b>HTTP invoker is the recommended protocol for Java-to-Java remoting.</b>
* It is more powerful and more extensible than Hessian and Burlap, at the
* expense of being tied to Java. Nevertheless, it is as easy to set up as
* Hessian and Burlap, which is its main advantage compared to RMI.
*
* <p><b>WARNING: Be aware of vulnerabilities due to unsafe Java deserialization:
* Manipulated input streams could lead to unwanted code execution on the server
* during the deserialization step. As a consequence, do not expose HTTP invoker
* endpoints to untrusted clients but rather just between your own services.</b>
* In general, we strongly recommend any other message format (e.g. JSON) instead.
*
* @author Juergen Hoeller
* @since 1.1
* @see HttpInvokerClientInterceptor
* @see HttpInvokerProxyFactoryBean
* @see com.fr.third.springframework.remoting.rmi.RmiServiceExporter
* @see com.fr.third.springframework.remoting.caucho.HessianServiceExporter
* @see com.fr.third.springframework.remoting.caucho.BurlapServiceExporter
*/
public class HttpInvokerServiceExporter extends RemoteInvocationSerializingExporter implements HttpRequestHandler {
/**
* Reads a remote invocation from the request, executes it,
* and writes the remote invocation result to the response.
* @see #readRemoteInvocation(HttpServletRequest)
* @see #invokeAndCreateResult(org.springframework.remoting.support.RemoteInvocation, Object)
* @see #writeRemoteInvocationResult(HttpServletRequest, HttpServletResponse, RemoteInvocationResult)
*/
@Override
public void handleRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
RemoteInvocation invocation = readRemoteInvocation(request);
RemoteInvocationResult result = invokeAndCreateResult(invocation, getProxy());
writeRemoteInvocationResult(request, response, result);
}
catch (ClassNotFoundException ex) {
throw new NestedServletException("Class not found during deserialization", ex);
}
}
/**
* Read a RemoteInvocation from the given HTTP request.
* <p>Delegates to {@link #readRemoteInvocation(HttpServletRequest, InputStream)} with
* the {@link HttpServletRequest#getInputStream() servlet request's input stream}.
* @param request current HTTP request
* @return the RemoteInvocation object
* @throws IOException in case of I/O failure
* @throws ClassNotFoundException if thrown by deserialization
*/
protected RemoteInvocation readRemoteInvocation(HttpServletRequest request)
throws IOException, ClassNotFoundException {
return readRemoteInvocation(request, request.getInputStream());
}
/**
* Deserialize a RemoteInvocation object from the given InputStream.
* <p>Gives {@link #decorateInputStream} a chance to decorate the stream
* first (for example, for custom encryption or compression). Creates a
* {@link com.fr.third.springframework.remoting.rmi.CodebaseAwareObjectInputStream}
* and calls {@link #doReadRemoteInvocation} to actually read the object.
* <p>Can be overridden for custom serialization of the invocation.
* @param request current HTTP request
* @param is the InputStream to read from
* @return the RemoteInvocation object
* @throws IOException in case of I/O failure
* @throws ClassNotFoundException if thrown during deserialization
*/
protected RemoteInvocation readRemoteInvocation(HttpServletRequest request, InputStream is)
throws IOException, ClassNotFoundException {
ObjectInputStream ois = createObjectInputStream(decorateInputStream(request, is));
try {
return doReadRemoteInvocation(ois);
}
finally {
ois.close();
}
}
/**
* Return the InputStream to use for reading remote invocations,
* potentially decorating the given original InputStream.
* <p>The default implementation returns the given stream as-is.
* Can be overridden, for example, for custom encryption or compression.
* @param request current HTTP request
* @param is the original InputStream
* @return the potentially decorated InputStream
* @throws IOException in case of I/O failure
*/
protected InputStream decorateInputStream(HttpServletRequest request, InputStream is) throws IOException {
return is;
}
/**
* Write the given RemoteInvocationResult to the given HTTP response.
* @param request current HTTP request
* @param response current HTTP response
* @param result the RemoteInvocationResult object
* @throws IOException in case of I/O failure
*/
protected void writeRemoteInvocationResult(
HttpServletRequest request, HttpServletResponse response, RemoteInvocationResult result)
throws IOException {
response.setContentType(getContentType());
writeRemoteInvocationResult(request, response, result, response.getOutputStream());
}
/**
* Serialize the given RemoteInvocation to the given OutputStream.
* <p>The default implementation gives {@link #decorateOutputStream} a chance
* to decorate the stream first (for example, for custom encryption or compression).
* Creates an {@link java.io.ObjectOutputStream} for the final stream and calls
* {@link #doWriteRemoteInvocationResult} to actually write the object.
* <p>Can be overridden for custom serialization of the invocation.
* @param request current HTTP request
* @param response current HTTP response
* @param result the RemoteInvocationResult object
* @param os the OutputStream to write to
* @throws IOException in case of I/O failure
* @see #decorateOutputStream
* @see #doWriteRemoteInvocationResult
*/
protected void writeRemoteInvocationResult(
HttpServletRequest request, HttpServletResponse response, RemoteInvocationResult result, OutputStream os)
throws IOException {
ObjectOutputStream oos =
createObjectOutputStream(new FlushGuardedOutputStream(decorateOutputStream(request, response, os)));
try {
doWriteRemoteInvocationResult(result, oos);
}
finally {
oos.close();
}
}
/**
* Return the OutputStream to use for writing remote invocation results,
* potentially decorating the given original OutputStream.
* <p>The default implementation returns the given stream as-is.
* Can be overridden, for example, for custom encryption or compression.
* @param request current HTTP request
* @param response current HTTP response
* @param os the original OutputStream
* @return the potentially decorated OutputStream
* @throws IOException in case of I/O failure
*/
protected OutputStream decorateOutputStream(
HttpServletRequest request, HttpServletResponse response, OutputStream os) throws IOException {
return os;
}
/**
* Decorate an {@code OutputStream} to guard against {@code flush()} calls,
* which are turned into no-ops.
* <p>Because {@link ObjectOutputStream#close()} will in fact flush/drain
* the underlying stream twice, this {@link FilterOutputStream} will
* guard against individual flush calls. Multiple flush calls can lead
* to performance issues, since writes aren't gathered as they should be.
* @see <a href="https://jira.spring.io/browse/SPR-14040">SPR-14040</a>
*/
private static class FlushGuardedOutputStream extends FilterOutputStream {
public FlushGuardedOutputStream(OutputStream out) {
super(out);
}
@Override
public void flush() throws IOException {
// Do nothing on flush
}
}
}

232
fine-spring/src/main/java/com/fr/third/springframework/remoting/httpinvoker/SimpleHttpInvokerRequestExecutor.java

@ -1,232 +0,0 @@
/*
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fr.third.springframework.remoting.httpinvoker;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.Locale;
import java.util.zip.GZIPInputStream;
import com.fr.third.springframework.context.i18n.LocaleContext;
import com.fr.third.springframework.context.i18n.LocaleContextHolder;
import com.fr.third.springframework.remoting.support.RemoteInvocationResult;
import com.fr.third.springframework.util.StringUtils;
/**
* {@link com.fr.third.springframework.remoting.httpinvoker.HttpInvokerRequestExecutor} implementation
* that uses standard Java facilities to execute POST requests, without support for HTTP
* authentication or advanced configuration options.
*
* <p>Designed for easy subclassing, customizing specific template methods. However,
* consider {@code HttpComponentsHttpInvokerRequestExecutor} for more sophisticated needs:
* The standard {@link HttpURLConnection} class is rather limited in its capabilities.
*
* @author Juergen Hoeller
* @since 1.1
* @see java.net.HttpURLConnection
*/
public class SimpleHttpInvokerRequestExecutor extends AbstractHttpInvokerRequestExecutor {
private int connectTimeout = -1;
private int readTimeout = -1;
/**
* Set the underlying URLConnection's connect timeout (in milliseconds).
* A timeout value of 0 specifies an infinite timeout.
* <p>Default is the system's default timeout.
* @see URLConnection#setConnectTimeout(int)
*/
public void setConnectTimeout(int connectTimeout) {
this.connectTimeout = connectTimeout;
}
/**
* Set the underlying URLConnection's read timeout (in milliseconds).
* A timeout value of 0 specifies an infinite timeout.
* <p>Default is the system's default timeout.
* @see URLConnection#setReadTimeout(int)
*/
public void setReadTimeout(int readTimeout) {
this.readTimeout = readTimeout;
}
/**
* Execute the given request through a standard {@link HttpURLConnection}.
* <p>This method implements the basic processing workflow:
* The actual work happens in this class's template methods.
* @see #openConnection
* @see #prepareConnection
* @see #writeRequestBody
* @see #validateResponse
* @see #readResponseBody
*/
@Override
protected RemoteInvocationResult doExecuteRequest(
HttpInvokerClientConfiguration config, ByteArrayOutputStream baos)
throws IOException, ClassNotFoundException {
HttpURLConnection con = openConnection(config);
prepareConnection(con, baos.size());
writeRequestBody(config, con, baos);
validateResponse(config, con);
InputStream responseBody = readResponseBody(config, con);
return readRemoteInvocationResult(responseBody, config.getCodebaseUrl());
}
/**
* Open an {@link HttpURLConnection} for the given remote invocation request.
* @param config the HTTP invoker configuration that specifies the
* target service
* @return the HttpURLConnection for the given request
* @throws IOException if thrown by I/O methods
* @see java.net.URL#openConnection()
*/
protected HttpURLConnection openConnection(HttpInvokerClientConfiguration config) throws IOException {
URLConnection con = new URL(config.getServiceUrl()).openConnection();
if (!(con instanceof HttpURLConnection)) {
throw new IOException(
"Service URL [" + config.getServiceUrl() + "] does not resolve to an HTTP connection");
}
return (HttpURLConnection) con;
}
/**
* Prepare the given HTTP connection.
* <p>The default implementation specifies POST as method,
* "application/x-java-serialized-object" as "Content-Type" header,
* and the given content length as "Content-Length" header.
* @param connection the HTTP connection to prepare
* @param contentLength the length of the content to send
* @throws IOException if thrown by HttpURLConnection methods
* @see java.net.HttpURLConnection#setRequestMethod
* @see java.net.HttpURLConnection#setRequestProperty
*/
protected void prepareConnection(HttpURLConnection connection, int contentLength) throws IOException {
if (this.connectTimeout >= 0) {
connection.setConnectTimeout(this.connectTimeout);
}
if (this.readTimeout >= 0) {
connection.setReadTimeout(this.readTimeout);
}
connection.setDoOutput(true);
connection.setRequestMethod(HTTP_METHOD_POST);
connection.setRequestProperty(HTTP_HEADER_CONTENT_TYPE, getContentType());
connection.setRequestProperty(HTTP_HEADER_CONTENT_LENGTH, Integer.toString(contentLength));
LocaleContext localeContext = LocaleContextHolder.getLocaleContext();
if (localeContext != null) {
Locale locale = localeContext.getLocale();
if (locale != null) {
connection.setRequestProperty(HTTP_HEADER_ACCEPT_LANGUAGE, StringUtils.toLanguageTag(locale));
}
}
if (isAcceptGzipEncoding()) {
connection.setRequestProperty(HTTP_HEADER_ACCEPT_ENCODING, ENCODING_GZIP);
}
}
/**
* Set the given serialized remote invocation as request body.
* <p>The default implementation simply write the serialized invocation to the
* HttpURLConnection's OutputStream. This can be overridden, for example, to write
* a specific encoding and potentially set appropriate HTTP request headers.
* @param config the HTTP invoker configuration that specifies the target service
* @param con the HttpURLConnection to write the request body to
* @param baos the ByteArrayOutputStream that contains the serialized
* RemoteInvocation object
* @throws IOException if thrown by I/O methods
* @see java.net.HttpURLConnection#getOutputStream()
* @see java.net.HttpURLConnection#setRequestProperty
*/
protected void writeRequestBody(
HttpInvokerClientConfiguration config, HttpURLConnection con, ByteArrayOutputStream baos)
throws IOException {
baos.writeTo(con.getOutputStream());
}
/**
* Validate the given response as contained in the {@link HttpURLConnection} object,
* throwing an exception if it does not correspond to a successful HTTP response.
* <p>Default implementation rejects any HTTP status code beyond 2xx, to avoid
* parsing the response body and trying to deserialize from a corrupted stream.
* @param config the HTTP invoker configuration that specifies the target service
* @param con the HttpURLConnection to validate
* @throws IOException if validation failed
* @see java.net.HttpURLConnection#getResponseCode()
*/
protected void validateResponse(HttpInvokerClientConfiguration config, HttpURLConnection con)
throws IOException {
if (con.getResponseCode() >= 300) {
throw new IOException(
"Did not receive successful HTTP response: status code = " + con.getResponseCode() +
", status message = [" + con.getResponseMessage() + "]");
}
}
/**
* Extract the response body from the given executed remote invocation
* request.
* <p>The default implementation simply reads the serialized invocation
* from the HttpURLConnection's InputStream. If the response is recognized
* as GZIP response, the InputStream will get wrapped in a GZIPInputStream.
* @param config the HTTP invoker configuration that specifies the target service
* @param con the HttpURLConnection to read the response body from
* @return an InputStream for the response body
* @throws IOException if thrown by I/O methods
* @see #isGzipResponse
* @see java.util.zip.GZIPInputStream
* @see java.net.HttpURLConnection#getInputStream()
* @see java.net.HttpURLConnection#getHeaderField(int)
* @see java.net.HttpURLConnection#getHeaderFieldKey(int)
*/
protected InputStream readResponseBody(HttpInvokerClientConfiguration config, HttpURLConnection con)
throws IOException {
if (isGzipResponse(con)) {
// GZIP response found - need to unzip.
return new GZIPInputStream(con.getInputStream());
}
else {
// Plain response found.
return con.getInputStream();
}
}
/**
* Determine whether the given response is a GZIP response.
* <p>Default implementation checks whether the HTTP "Content-Encoding"
* header contains "gzip" (in any casing).
* @param con the HttpURLConnection to check
*/
protected boolean isGzipResponse(HttpURLConnection con) {
String encodingHeader = con.getHeaderField(HTTP_HEADER_CONTENT_ENCODING);
return (encodingHeader != null && encodingHeader.toLowerCase().contains(ENCODING_GZIP));
}
}

184
fine-spring/src/main/java/com/fr/third/springframework/remoting/httpinvoker/SimpleHttpInvokerServiceExporter.java

@ -1,184 +0,0 @@
/*
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fr.third.springframework.remoting.httpinvoker;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.fr.third.springframework.lang.UsesSunHttpServer;
import com.fr.third.springframework.remoting.rmi.RemoteInvocationSerializingExporter;
import com.fr.third.springframework.remoting.support.RemoteInvocation;
import com.fr.third.springframework.remoting.support.RemoteInvocationResult;
/**
* HTTP request handler that exports the specified service bean as
* HTTP invoker service endpoint, accessible via an HTTP invoker proxy.
* Designed for Sun's JRE 1.6 HTTP server, implementing the
* {@link com.sun.net.httpserver.HttpHandler} interface.
*
* <p>Deserializes remote invocation objects and serializes remote invocation
* result objects. Uses Java serialization just like RMI, but provides the
* same ease of setup as Caucho's HTTP-based Hessian and Burlap protocols.
*
* <p><b>HTTP invoker is the recommended protocol for Java-to-Java remoting.</b>
* It is more powerful and more extensible than Hessian and Burlap, at the
* expense of being tied to Java. Nevertheless, it is as easy to set up as
* Hessian and Burlap, which is its main advantage compared to RMI.
*
* <p><b>WARNING: Be aware of vulnerabilities due to unsafe Java deserialization:
* Manipulated input streams could lead to unwanted code execution on the server
* during the deserialization step. As a consequence, do not expose HTTP invoker
* endpoints to untrusted clients but rather just between your own services.</b>
* In general, we strongly recommend any other message format (e.g. JSON) instead.
*
* @author Juergen Hoeller
* @since 2.5.1
* @see com.fr.third.springframework.remoting.httpinvoker.HttpInvokerClientInterceptor
* @see com.fr.third.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean
* @see com.fr.third.springframework.remoting.caucho.SimpleHessianServiceExporter
* @see com.fr.third.springframework.remoting.caucho.SimpleBurlapServiceExporter
*/
@UsesSunHttpServer
public class SimpleHttpInvokerServiceExporter extends RemoteInvocationSerializingExporter implements HttpHandler {
/**
* Reads a remote invocation from the request, executes it,
* and writes the remote invocation result to the response.
* @see #readRemoteInvocation(HttpExchange)
* @see #invokeAndCreateResult(RemoteInvocation, Object)
* @see #writeRemoteInvocationResult(HttpExchange, RemoteInvocationResult)
*/
@Override
public void handle(HttpExchange exchange) throws IOException {
try {
RemoteInvocation invocation = readRemoteInvocation(exchange);
RemoteInvocationResult result = invokeAndCreateResult(invocation, getProxy());
writeRemoteInvocationResult(exchange, result);
exchange.close();
}
catch (ClassNotFoundException ex) {
exchange.sendResponseHeaders(500, -1);
logger.error("Class not found during deserialization", ex);
}
}
/**
* Read a RemoteInvocation from the given HTTP request.
* <p>Delegates to {@link #readRemoteInvocation(HttpExchange, InputStream)}
* with the {@link HttpExchange#getRequestBody()} request's input stream}.
* @param exchange current HTTP request/response
* @return the RemoteInvocation object
* @throws java.io.IOException in case of I/O failure
* @throws ClassNotFoundException if thrown by deserialization
*/
protected RemoteInvocation readRemoteInvocation(HttpExchange exchange)
throws IOException, ClassNotFoundException {
return readRemoteInvocation(exchange, exchange.getRequestBody());
}
/**
* Deserialize a RemoteInvocation object from the given InputStream.
* <p>Gives {@link #decorateInputStream} a chance to decorate the stream
* first (for example, for custom encryption or compression). Creates a
* {@link com.fr.third.springframework.remoting.rmi.CodebaseAwareObjectInputStream}
* and calls {@link #doReadRemoteInvocation} to actually read the object.
* <p>Can be overridden for custom serialization of the invocation.
* @param exchange current HTTP request/response
* @param is the InputStream to read from
* @return the RemoteInvocation object
* @throws java.io.IOException in case of I/O failure
* @throws ClassNotFoundException if thrown during deserialization
*/
protected RemoteInvocation readRemoteInvocation(HttpExchange exchange, InputStream is)
throws IOException, ClassNotFoundException {
ObjectInputStream ois = createObjectInputStream(decorateInputStream(exchange, is));
return doReadRemoteInvocation(ois);
}
/**
* Return the InputStream to use for reading remote invocations,
* potentially decorating the given original InputStream.
* <p>The default implementation returns the given stream as-is.
* Can be overridden, for example, for custom encryption or compression.
* @param exchange current HTTP request/response
* @param is the original InputStream
* @return the potentially decorated InputStream
* @throws java.io.IOException in case of I/O failure
*/
protected InputStream decorateInputStream(HttpExchange exchange, InputStream is) throws IOException {
return is;
}
/**
* Write the given RemoteInvocationResult to the given HTTP response.
* @param exchange current HTTP request/response
* @param result the RemoteInvocationResult object
* @throws java.io.IOException in case of I/O failure
*/
protected void writeRemoteInvocationResult(HttpExchange exchange, RemoteInvocationResult result)
throws IOException {
exchange.getResponseHeaders().set("Content-Type", getContentType());
exchange.sendResponseHeaders(200, 0);
writeRemoteInvocationResult(exchange, result, exchange.getResponseBody());
}
/**
* Serialize the given RemoteInvocation to the given OutputStream.
* <p>The default implementation gives {@link #decorateOutputStream} a chance
* to decorate the stream first (for example, for custom encryption or compression).
* Creates an {@link java.io.ObjectOutputStream} for the final stream and calls
* {@link #doWriteRemoteInvocationResult} to actually write the object.
* <p>Can be overridden for custom serialization of the invocation.
* @param exchange current HTTP request/response
* @param result the RemoteInvocationResult object
* @param os the OutputStream to write to
* @throws java.io.IOException in case of I/O failure
* @see #decorateOutputStream
* @see #doWriteRemoteInvocationResult
*/
protected void writeRemoteInvocationResult(
HttpExchange exchange, RemoteInvocationResult result, OutputStream os) throws IOException {
ObjectOutputStream oos = createObjectOutputStream(decorateOutputStream(exchange, os));
doWriteRemoteInvocationResult(result, oos);
oos.flush();
}
/**
* Return the OutputStream to use for writing remote invocation results,
* potentially decorating the given original OutputStream.
* <p>The default implementation returns the given stream as-is.
* Can be overridden, for example, for custom encryption or compression.
* @param exchange current HTTP request/response
* @param os the original OutputStream
* @return the potentially decorated OutputStream
* @throws java.io.IOException in case of I/O failure
*/
protected OutputStream decorateOutputStream(HttpExchange exchange, OutputStream os) throws IOException {
return os;
}
}

11
fine-spring/src/main/java/com/fr/third/springframework/remoting/httpinvoker/package-info.java

@ -1,11 +0,0 @@
/**
* Remoting classes for transparent Java-to-Java remoting via HTTP invokers.
* Uses Java serialization just like RMI, but provides the same ease of setup
* as Caucho's HTTP-based Hessian and Burlap protocols.
*
* <p><b>HTTP invoker is the recommended protocol for Java-to-Java remoting.</b>
* It is more powerful and more extensible than Hessian and Burlap, at the
* expense of being tied to Java. Neverthelesss, it is as easy to set up as
* Hessian and Burlap, which is its main advantage compared to RMI.
*/
package com.fr.third.springframework.remoting.httpinvoker;

119
fine-spring/src/main/java/com/fr/third/springframework/remoting/rmi/CodebaseAwareObjectInputStream.java

@ -1,119 +0,0 @@
/*
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fr.third.springframework.remoting.rmi;
import java.io.IOException;
import java.io.InputStream;
import java.rmi.server.RMIClassLoader;
import com.fr.third.springframework.core.ConfigurableObjectInputStream;
/**
* Special ObjectInputStream subclass that falls back to a specified codebase
* to load classes from if not found locally. In contrast to standard RMI
* conventions for dynamic class download, it is the client that determines
* the codebase URL here, rather than the "java.rmi.server.codebase" system
* property on the server.
*
* <p>Uses the JDK's RMIClassLoader to load classes from the specified codebase.
* The codebase can consist of multiple URLs, separated by spaces.
* Note that RMIClassLoader requires a SecurityManager to be set, like when
* using dynamic class download with standard RMI! (See the RMI documentation
* for details.)
*
* <p>Despite residing in the RMI package, this class is <i>not</i> used for
* RmiClientInterceptor, which uses the standard RMI infrastructure instead
* and thus is only able to rely on RMI's standard dynamic class download via
* "java.rmi.server.codebase". CodebaseAwareObjectInputStream is used by
* HttpInvokerClientInterceptor (see the "codebaseUrl" property there).
*
* <p>Thanks to Lionel Mestre for suggesting the option and providing
* a prototype!
*
* @author Juergen Hoeller
* @since 1.1.3
* @see java.rmi.server.RMIClassLoader
* @see RemoteInvocationSerializingExporter#createObjectInputStream
* @see com.fr.third.springframework.remoting.httpinvoker.HttpInvokerClientInterceptor#setCodebaseUrl
*/
public class CodebaseAwareObjectInputStream extends ConfigurableObjectInputStream {
private final String codebaseUrl;
/**
* Create a new CodebaseAwareObjectInputStream for the given InputStream and codebase.
* @param in the InputStream to read from
* @param codebaseUrl the codebase URL to load classes from if not found locally
* (can consist of multiple URLs, separated by spaces)
* @see java.io.ObjectInputStream#ObjectInputStream(java.io.InputStream)
*/
public CodebaseAwareObjectInputStream(InputStream in, String codebaseUrl) throws IOException {
this(in, null, codebaseUrl);
}
/**
* Create a new CodebaseAwareObjectInputStream for the given InputStream and codebase.
* @param in the InputStream to read from
* @param classLoader the ClassLoader to use for loading local classes
* (may be {@code null} to indicate RMI's default ClassLoader)
* @param codebaseUrl the codebase URL to load classes from if not found locally
* (can consist of multiple URLs, separated by spaces)
* @see java.io.ObjectInputStream#ObjectInputStream(java.io.InputStream)
*/
public CodebaseAwareObjectInputStream(
InputStream in, ClassLoader classLoader, String codebaseUrl) throws IOException {
super(in, classLoader);
this.codebaseUrl = codebaseUrl;
}
/**
* Create a new CodebaseAwareObjectInputStream for the given InputStream and codebase.
* @param in the InputStream to read from
* @param classLoader the ClassLoader to use for loading local classes
* (may be {@code null} to indicate RMI's default ClassLoader)
* @param acceptProxyClasses whether to accept deserialization of proxy classes
* (may be deactivated as a security measure)
* @see java.io.ObjectInputStream#ObjectInputStream(java.io.InputStream)
*/
public CodebaseAwareObjectInputStream(
InputStream in, ClassLoader classLoader, boolean acceptProxyClasses) throws IOException {
super(in, classLoader, acceptProxyClasses);
this.codebaseUrl = null;
}
@Override
protected Class<?> resolveFallbackIfPossible(String className, ClassNotFoundException ex)
throws IOException, ClassNotFoundException {
// If codebaseUrl is set, try to load the class with the RMIClassLoader.
// Else, propagate the ClassNotFoundException.
if (this.codebaseUrl == null) {
throw ex;
}
return RMIClassLoader.loadClass(this.codebaseUrl, className);
}
@Override
protected ClassLoader getFallbackClassLoader() throws IOException {
return RMIClassLoader.getClassLoader(this.codebaseUrl);
}
}

510
fine-spring/src/main/java/com/fr/third/springframework/remoting/rmi/JndiRmiClientInterceptor.java

@ -1,510 +0,0 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fr.third.springframework.remoting.rmi;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.rmi.RemoteException;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.rmi.PortableRemoteObject;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.omg.CORBA.OBJECT_NOT_EXIST;
import org.omg.CORBA.SystemException;
import com.fr.third.springframework.aop.support.AopUtils;
import com.fr.third.springframework.beans.factory.InitializingBean;
import com.fr.third.springframework.jndi.JndiObjectLocator;
import com.fr.third.springframework.remoting.RemoteAccessException;
import com.fr.third.springframework.remoting.RemoteConnectFailureException;
import com.fr.third.springframework.remoting.RemoteInvocationFailureException;
import com.fr.third.springframework.remoting.RemoteLookupFailureException;
import com.fr.third.springframework.remoting.support.DefaultRemoteInvocationFactory;
import com.fr.third.springframework.remoting.support.RemoteInvocation;
import com.fr.third.springframework.remoting.support.RemoteInvocationFactory;
import com.fr.third.springframework.util.ReflectionUtils;
/**
* {@link org.aopalliance.intercept.MethodInterceptor} for accessing RMI services
* from JNDI.Typically used for RMI-IIOP, but can also be used for EJB home objects
* (for example, a Stateful Session Bean home). In contrast to a plain JNDI lookup,
* this accessor also performs narrowing through PortableRemoteObject.
*
* <p>With conventional RMI services, this invoker is typically used with the RMI
* service interface. Alternatively, this invoker can also proxy a remote RMI service
* with a matching non-RMI business interface, i.e. an interface that mirrors the RMI
* service methods but does not declare RemoteExceptions. In the latter case,
* RemoteExceptions thrown by the RMI stub will automatically get converted to
* Spring's unchecked RemoteAccessException.
*
* <p>The JNDI environment can be specified as "jndiEnvironment" property,
* or be configured in a {@code jndi.properties} file or as system properties.
* For example:
*
* <pre class="code">&lt;property name="jndiEnvironment"&gt;
* &lt;props>
* &lt;prop key="java.naming.factory.initial"&gt;com.sun.jndi.cosnaming.CNCtxFactory&lt;/prop&gt;
* &lt;prop key="java.naming.provider.url"&gt;iiop://localhost:1050&lt;/prop&gt;
* &lt;/props&gt;
* &lt;/property&gt;</pre>
*
* @author Juergen Hoeller
* @since 1.1
* @see #setJndiTemplate
* @see #setJndiEnvironment
* @see #setJndiName
* @see JndiRmiServiceExporter
* @see JndiRmiProxyFactoryBean
* @see com.fr.third.springframework.remoting.RemoteAccessException
* @see java.rmi.RemoteException
* @see java.rmi.Remote
*/
public class JndiRmiClientInterceptor extends JndiObjectLocator implements MethodInterceptor, InitializingBean {
// 定制 本类中注释掉的内容,见
// https://code.fineres.com/projects/CORE/repos/base-third/commits/5b3f31597873b165b6a154393ee4ade942beec0a#fine-spring/src/com/fr/third/springframework/remoting/rmi/JndiRmiClientInterceptor.java
private Class<?> serviceInterface;
private RemoteInvocationFactory remoteInvocationFactory = new DefaultRemoteInvocationFactory();
private boolean lookupStubOnStartup = true;
private boolean cacheStub = true;
private boolean refreshStubOnConnectFailure = false;
private boolean exposeAccessContext = false;
private Object cachedStub;
private final Object stubMonitor = new Object();
/**
* Set the interface of the service to access.
* The interface must be suitable for the particular service and remoting tool.
* <p>Typically required to be able to create a suitable service proxy,
* but can also be optional if the lookup returns a typed stub.
*/
public void setServiceInterface(Class<?> serviceInterface) {
if (serviceInterface != null && !serviceInterface.isInterface()) {
throw new IllegalArgumentException("'serviceInterface' must be an interface");
}
this.serviceInterface = serviceInterface;
}
/**
* Return the interface of the service to access.
*/
public Class<?> getServiceInterface() {
return this.serviceInterface;
}
/**
* Set the RemoteInvocationFactory to use for this accessor.
* Default is a {@link DefaultRemoteInvocationFactory}.
* <p>A custom invocation factory can add further context information
* to the invocation, for example user credentials.
*/
public void setRemoteInvocationFactory(RemoteInvocationFactory remoteInvocationFactory) {
this.remoteInvocationFactory = remoteInvocationFactory;
}
/**
* Return the RemoteInvocationFactory used by this accessor.
*/
public RemoteInvocationFactory getRemoteInvocationFactory() {
return this.remoteInvocationFactory;
}
/**
* Set whether to look up the RMI stub on startup. Default is "true".
* <p>Can be turned off to allow for late start of the RMI server.
* In this case, the RMI stub will be fetched on first access.
* @see #setCacheStub
*/
public void setLookupStubOnStartup(boolean lookupStubOnStartup) {
this.lookupStubOnStartup = lookupStubOnStartup;
}
/**
* Set whether to cache the RMI stub once it has been located.
* Default is "true".
* <p>Can be turned off to allow for hot restart of the RMI server.
* In this case, the RMI stub will be fetched for each invocation.
* @see #setLookupStubOnStartup
*/
public void setCacheStub(boolean cacheStub) {
this.cacheStub = cacheStub;
}
/**
* Set whether to refresh the RMI stub on connect failure.
* Default is "false".
* <p>Can be turned on to allow for hot restart of the RMI server.
* If a cached RMI stub throws an RMI exception that indicates a
* remote connect failure, a fresh proxy will be fetched and the
* invocation will be retried.
* @see java.rmi.ConnectException
* @see java.rmi.ConnectIOException
* @see java.rmi.NoSuchObjectException
*/
public void setRefreshStubOnConnectFailure(boolean refreshStubOnConnectFailure) {
this.refreshStubOnConnectFailure = refreshStubOnConnectFailure;
}
/**
* Set whether to expose the JNDI environment context for all access to the target
* RMI stub, i.e. for all method invocations on the exposed object reference.
* <p>Default is "false", i.e. to only expose the JNDI context for object lookup.
* Switch this flag to "true" in order to expose the JNDI environment (including
* the authorization context) for each RMI invocation, as needed by WebLogic
* for RMI stubs with authorization requirements.
*/
public void setExposeAccessContext(boolean exposeAccessContext) {
this.exposeAccessContext = exposeAccessContext;
}
@Override
public void afterPropertiesSet() throws NamingException {
super.afterPropertiesSet();
prepare();
}
/**
* Fetches the RMI stub on startup, if necessary.
* @throws RemoteLookupFailureException if RMI stub creation failed
* @see #setLookupStubOnStartup
* @see #lookupStub
*/
public void prepare() throws RemoteLookupFailureException {
// Cache RMI stub on initialization?
if (this.lookupStubOnStartup) {
Object remoteObj = lookupStub();
if (logger.isDebugEnabled()) {
if (remoteObj instanceof RmiInvocationHandler) {
logger.debug("JNDI RMI object [" + getJndiName() + "] is an RMI invoker");
}
else if (getServiceInterface() != null) {
boolean isImpl = getServiceInterface().isInstance(remoteObj);
logger.debug("Using service interface [" + getServiceInterface().getName() +
"] for JNDI RMI object [" + getJndiName() + "] - " +
(!isImpl ? "not " : "") + "directly implemented");
}
}
if (this.cacheStub) {
this.cachedStub = remoteObj;
}
}
}
/**
* Create the RMI stub, typically by looking it up.
* <p>Called on interceptor initialization if "cacheStub" is "true";
* else called for each invocation by {@link #getStub()}.
* <p>The default implementation retrieves the service from the
* JNDI environment. This can be overridden in subclasses.
* @return the RMI stub to store in this interceptor
* @throws RemoteLookupFailureException if RMI stub creation failed
* @see #setCacheStub
* @see #lookup
*/
protected Object lookupStub() throws RemoteLookupFailureException {
try {
// Object stub = lookup();
// if (getServiceInterface() != null && !(stub instanceof RmiInvocationHandler)) {
// try {
// stub = PortableRemoteObject.narrow(stub, getServiceInterface());
// }
// catch (ClassCastException ex) {
// throw new RemoteLookupFailureException(
// "Could not narrow RMI stub to service interface [" + getServiceInterface().getName() + "]", ex);
// }
// }
return lookup();
}
catch (NamingException ex) {
throw new RemoteLookupFailureException("JNDI lookup for RMI service [" + getJndiName() + "] failed", ex);
}
}
/**
* Return the RMI stub to use. Called for each invocation.
* <p>The default implementation returns the stub created on initialization,
* if any. Else, it invokes {@link #lookupStub} to get a new stub for
* each invocation. This can be overridden in subclasses, for example in
* order to cache a stub for a given amount of time before recreating it,
* or to test the stub whether it is still alive.
* @return the RMI stub to use for an invocation
* @throws NamingException if stub creation failed
* @throws RemoteLookupFailureException if RMI stub creation failed
*/
protected Object getStub() throws NamingException, RemoteLookupFailureException {
if (!this.cacheStub || (this.lookupStubOnStartup && !this.refreshStubOnConnectFailure)) {
return (this.cachedStub != null ? this.cachedStub : lookupStub());
}
else {
synchronized (this.stubMonitor) {
if (this.cachedStub == null) {
this.cachedStub = lookupStub();
}
return this.cachedStub;
}
}
}
/**
* Fetches an RMI stub and delegates to {@link #doInvoke}.
* If configured to refresh on connect failure, it will call
* {@link #refreshAndRetry} on corresponding RMI exceptions.
* @see #getStub
* @see #doInvoke
* @see #refreshAndRetry
* @see java.rmi.ConnectException
* @see java.rmi.ConnectIOException
* @see java.rmi.NoSuchObjectException
*/
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
Object stub;
try {
stub = getStub();
}
catch (NamingException ex) {
throw new RemoteLookupFailureException("JNDI lookup for RMI service [" + getJndiName() + "] failed", ex);
}
Context ctx = (this.exposeAccessContext ? getJndiTemplate().getContext() : null);
try {
return doInvoke(invocation, stub);
}
catch (RemoteConnectFailureException ex) {
return handleRemoteConnectFailure(invocation, ex);
}
catch (RemoteException ex) {
if (isConnectFailure(ex)) {
return handleRemoteConnectFailure(invocation, ex);
}
else {
throw ex;
}
}
// catch (SystemException ex) {
// if (isConnectFailure(ex)) {
// return handleRemoteConnectFailure(invocation, ex);
// }
// else {
// throw ex;
// }
// }
finally {
getJndiTemplate().releaseContext(ctx);
}
}
/**
* Determine whether the given RMI exception indicates a connect failure.
* <p>The default implementation delegates to
* {@link RmiClientInterceptorUtils#isConnectFailure}.
* @param ex the RMI exception to check
* @return whether the exception should be treated as connect failure
*/
protected boolean isConnectFailure(RemoteException ex) {
return RmiClientInterceptorUtils.isConnectFailure(ex);
}
// /**
// * Determine whether the given CORBA exception indicates a connect failure.
// * <p>The default implementation checks for CORBA's
// * {@link org.omg.CORBA.OBJECT_NOT_EXIST} exception.
// * @param ex the RMI exception to check
// * @return whether the exception should be treated as connect failure
// */
// protected boolean isConnectFailure(SystemException ex) {
// return (ex instanceof OBJECT_NOT_EXIST);
// }
/**
* Refresh the stub and retry the remote invocation if necessary.
* <p>If not configured to refresh on connect failure, this method
* simply rethrows the original exception.
* @param invocation the invocation that failed
* @param ex the exception raised on remote invocation
* @return the result value of the new invocation, if succeeded
* @throws Throwable an exception raised by the new invocation, if failed too.
*/
private Object handleRemoteConnectFailure(MethodInvocation invocation, Exception ex) throws Throwable {
if (this.refreshStubOnConnectFailure) {
if (logger.isDebugEnabled()) {
logger.debug("Could not connect to RMI service [" + getJndiName() + "] - retrying", ex);
}
else if (logger.isWarnEnabled()) {
logger.warn("Could not connect to RMI service [" + getJndiName() + "] - retrying");
}
return refreshAndRetry(invocation);
}
else {
throw ex;
}
}
/**
* Refresh the RMI stub and retry the given invocation.
* Called by invoke on connect failure.
* @param invocation the AOP method invocation
* @return the invocation result, if any
* @throws Throwable in case of invocation failure
* @see #invoke
*/
protected Object refreshAndRetry(MethodInvocation invocation) throws Throwable {
Object freshStub;
synchronized (this.stubMonitor) {
this.cachedStub = null;
freshStub = lookupStub();
if (this.cacheStub) {
this.cachedStub = freshStub;
}
}
return doInvoke(invocation, freshStub);
}
/**
* Perform the given invocation on the given RMI stub.
* @param invocation the AOP method invocation
* @param stub the RMI stub to invoke
* @return the invocation result, if any
* @throws Throwable in case of invocation failure
*/
protected Object doInvoke(MethodInvocation invocation, Object stub) throws Throwable {
if (stub instanceof RmiInvocationHandler) {
// RMI invoker
try {
return doInvoke(invocation, (RmiInvocationHandler) stub);
}
catch (RemoteException ex) {
throw convertRmiAccessException(ex, invocation.getMethod());
}
// catch (SystemException ex) {
// throw convertCorbaAccessException(ex, invocation.getMethod());
// }
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
catch (Throwable ex) {
throw new RemoteInvocationFailureException("Invocation of method [" + invocation.getMethod() +
"] failed in RMI service [" + getJndiName() + "]", ex);
}
}
else {
// traditional RMI stub
try {
return RmiClientInterceptorUtils.invokeRemoteMethod(invocation, stub);
}
catch (InvocationTargetException ex) {
Throwable targetEx = ex.getTargetException();
if (targetEx instanceof RemoteException) {
throw convertRmiAccessException((RemoteException) targetEx, invocation.getMethod());
}
// else if (targetEx instanceof SystemException) {
// throw convertCorbaAccessException((SystemException) targetEx, invocation.getMethod());
// }
else {
throw targetEx;
}
}
}
}
/**
* Apply the given AOP method invocation to the given {@link RmiInvocationHandler}.
* <p>The default implementation delegates to {@link #createRemoteInvocation}.
* @param methodInvocation the current AOP method invocation
* @param invocationHandler the RmiInvocationHandler to apply the invocation to
* @return the invocation result
* @throws RemoteException in case of communication errors
* @throws NoSuchMethodException if the method name could not be resolved
* @throws IllegalAccessException if the method could not be accessed
* @throws InvocationTargetException if the method invocation resulted in an exception
* @see com.fr.third.springframework.remoting.support.RemoteInvocation
*/
protected Object doInvoke(MethodInvocation methodInvocation, RmiInvocationHandler invocationHandler)
throws RemoteException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
if (AopUtils.isToStringMethod(methodInvocation.getMethod())) {
return "RMI invoker proxy for service URL [" + getJndiName() + "]";
}
return invocationHandler.invoke(createRemoteInvocation(methodInvocation));
}
/**
* Create a new RemoteInvocation object for the given AOP method invocation.
* <p>The default implementation delegates to the configured
* {@link #setRemoteInvocationFactory RemoteInvocationFactory}.
* This can be overridden in subclasses in order to provide custom RemoteInvocation
* subclasses, containing additional invocation parameters (e.g. user credentials).
* <p>Note that it is preferable to build a custom RemoteInvocationFactory
* as a reusable strategy, instead of overriding this method.
* @param methodInvocation the current AOP method invocation
* @return the RemoteInvocation object
* @see RemoteInvocationFactory#createRemoteInvocation
*/
protected RemoteInvocation createRemoteInvocation(MethodInvocation methodInvocation) {
return getRemoteInvocationFactory().createRemoteInvocation(methodInvocation);
}
/**
* Convert the given RMI RemoteException that happened during remote access
* to Spring's RemoteAccessException if the method signature does not declare
* RemoteException. Else, return the original RemoteException.
* @param method the invoked method
* @param ex the RemoteException that happened
* @return the exception to be thrown to the caller
*/
private Exception convertRmiAccessException(RemoteException ex, Method method) {
return RmiClientInterceptorUtils.convertRmiAccessException(method, ex, isConnectFailure(ex), getJndiName());
}
// /**
// * Convert the given CORBA SystemException that happened during remote access
// * to Spring's RemoteAccessException if the method signature does not declare
// * RemoteException. Else, return the SystemException wrapped in a RemoteException.
// * @param method the invoked method
// * @param ex the RemoteException that happened
// * @return the exception to be thrown to the caller
// */
// private Exception convertCorbaAccessException(SystemException ex, Method method) {
// if (ReflectionUtils.declaresException(method, RemoteException.class)) {
// // A traditional RMI service: wrap CORBA exceptions in standard RemoteExceptions.
// return new RemoteException("Failed to access CORBA service [" + getJndiName() + "]", ex);
// }
// else {
// if (isConnectFailure(ex)) {
// return new RemoteConnectFailureException("Could not connect to CORBA service [" + getJndiName() + "]", ex);
// }
// else {
// return new RemoteAccessException("Could not access CORBA service [" + getJndiName() + "]", ex);
// }
// }
// }
}

102
fine-spring/src/main/java/com/fr/third/springframework/remoting/rmi/JndiRmiProxyFactoryBean.java

@ -1,102 +0,0 @@
/*
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fr.third.springframework.remoting.rmi;
import javax.naming.NamingException;
import com.fr.third.springframework.aop.framework.ProxyFactory;
import com.fr.third.springframework.beans.factory.BeanClassLoaderAware;
import com.fr.third.springframework.beans.factory.FactoryBean;
import com.fr.third.springframework.util.ClassUtils;
/**
* {@link FactoryBean} for RMI proxies from JNDI.
*
* <p>Typically used for RMI-IIOP (CORBA), but can also be used for EJB home objects
* (for example, a Stateful Session Bean home). In contrast to a plain JNDI lookup,
* this accessor also performs narrowing through {@link javax.rmi.PortableRemoteObject}.
*
* <p>With conventional RMI services, this invoker is typically used with the RMI
* service interface. Alternatively, this invoker can also proxy a remote RMI service
* with a matching non-RMI business interface, i.e. an interface that mirrors the RMI
* service methods but does not declare RemoteExceptions. In the latter case,
* RemoteExceptions thrown by the RMI stub will automatically get converted to
* Spring's unchecked RemoteAccessException.
*
* <p>The JNDI environment can be specified as "jndiEnvironment" property,
* or be configured in a {@code jndi.properties} file or as system properties.
* For example:
*
* <pre class="code">&lt;property name="jndiEnvironment"&gt;
* &lt;props>
* &lt;prop key="java.naming.factory.initial"&gt;com.sun.jndi.cosnaming.CNCtxFactory&lt;/prop&gt;
* &lt;prop key="java.naming.provider.url"&gt;iiop://localhost:1050&lt;/prop&gt;
* &lt;/props&gt;
* &lt;/property&gt;</pre>
*
* @author Juergen Hoeller
* @since 1.1
* @see #setServiceInterface
* @see #setJndiName
* @see #setJndiTemplate
* @see #setJndiEnvironment
* @see #setJndiName
* @see JndiRmiServiceExporter
* @see com.fr.third.springframework.remoting.RemoteAccessException
* @see java.rmi.RemoteException
* @see java.rmi.Remote
* @see javax.rmi.PortableRemoteObject#narrow
*/
public class JndiRmiProxyFactoryBean extends JndiRmiClientInterceptor
implements FactoryBean<Object>, BeanClassLoaderAware {
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
private Object serviceProxy;
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.beanClassLoader = classLoader;
}
@Override
public void afterPropertiesSet() throws NamingException {
super.afterPropertiesSet();
if (getServiceInterface() == null) {
throw new IllegalArgumentException("Property 'serviceInterface' is required");
}
this.serviceProxy = new ProxyFactory(getServiceInterface(), this).getProxy(this.beanClassLoader);
}
@Override
public Object getObject() {
return this.serviceProxy;
}
@Override
public Class<?> getObjectType() {
return getServiceInterface();
}
@Override
public boolean isSingleton() {
return true;
}
}

149
fine-spring/src/main/java/com/fr/third/springframework/remoting/rmi/JndiRmiServiceExporter.java

@ -1,149 +0,0 @@
/*
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fr.third.springframework.remoting.rmi;
import java.rmi.NoSuchObjectException;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.util.Properties;
import javax.naming.NamingException;
import com.fr.third.springframework.beans.factory.DisposableBean;
import com.fr.third.springframework.beans.factory.InitializingBean;
import com.fr.third.springframework.jndi.JndiTemplate;
/**
* Service exporter which binds RMI services to JNDI.
* Typically used for RMI-IIOP (CORBA).
*
* You need to run "rmic" with the "-iiop" option to generate corresponding
* stubs and skeletons for each exported service.
*
* <p>Also supports exposing any non-RMI service via RMI invokers, to be accessed
* via {@link JndiRmiClientInterceptor} / {@link JndiRmiProxyFactoryBean}'s
* automatic detection of such invokers.
*
* <p>With an RMI invoker, RMI communication works on the {@link RmiInvocationHandler}
* level, needing only one stub for any service. Service interfaces do not have to
* extend {@code java.rmi.Remote} or throw {@code java.rmi.RemoteException}
* on all methods, but in and out parameters have to be serializable.
*
* <p>The JNDI environment can be specified as "jndiEnvironment" bean property,
* or be configured in a {@code jndi.properties} file or as system properties.
* For example:
*
* <pre class="code">&lt;property name="jndiEnvironment"&gt;
* &lt;props>
* &lt;prop key="java.naming.factory.initial"&gt;com.sun.jndi.cosnaming.CNCtxFactory&lt;/prop&gt;
* &lt;prop key="java.naming.provider.url"&gt;iiop://localhost:1050&lt;/prop&gt;
* &lt;/props&gt;
* &lt;/property&gt;</pre>
*
* @author Juergen Hoeller
* @since 1.1
* @see #setService
* @see #setJndiTemplate
* @see #setJndiEnvironment
* @see #setJndiName
* @see JndiRmiClientInterceptor
* @see JndiRmiProxyFactoryBean
*/
public class JndiRmiServiceExporter extends RmiBasedExporter implements InitializingBean, DisposableBean {
// 定制 本类中注释掉的内容,见
// https://code.fineres.com/projects/CORE/repos/base-third/commits/5b3f31597873b165b6a154393ee4ade942beec0a#fine-spring/src/com/fr/third/springframework/remoting/rmi/JndiRmiClientInterceptor.java
private JndiTemplate jndiTemplate = new JndiTemplate();
private String jndiName;
private Remote exportedObject;
/**
* Set the JNDI template to use for JNDI lookups.
* You can also specify JNDI environment settings via "jndiEnvironment".
* @see #setJndiEnvironment
*/
public void setJndiTemplate(JndiTemplate jndiTemplate) {
this.jndiTemplate = (jndiTemplate != null ? jndiTemplate : new JndiTemplate());
}
/**
* Set the JNDI environment to use for JNDI lookups.
* Creates a JndiTemplate with the given environment settings.
* @see #setJndiTemplate
*/
public void setJndiEnvironment(Properties jndiEnvironment) {
this.jndiTemplate = new JndiTemplate(jndiEnvironment);
}
/**
* Set the JNDI name of the exported RMI service.
*/
public void setJndiName(String jndiName) {
this.jndiName = jndiName;
}
@Override
public void afterPropertiesSet() throws NamingException, RemoteException {
prepare();
}
/**
* Initialize this service exporter, binding the specified service to JNDI.
* @throws NamingException if service binding failed
* @throws RemoteException if service export failed
*/
public void prepare() throws NamingException, RemoteException {
if (this.jndiName == null) {
throw new IllegalArgumentException("Property 'jndiName' is required");
}
// Initialize and cache exported object.
this.exportedObject = getObjectToExport();
// PortableRemoteObject.exportObject(this.exportedObject);
rebind();
}
/**
* Rebind the specified service to JNDI, for recovering in case
* of the target registry having been restarted.
* @throws NamingException if service binding failed
*/
public void rebind() throws NamingException {
if (logger.isInfoEnabled()) {
logger.info("Binding RMI service to JNDI location [" + this.jndiName + "]");
}
this.jndiTemplate.rebind(this.jndiName, this.exportedObject);
}
/**
* Unbind the RMI service from JNDI on bean factory shutdown.
*/
@Override
public void destroy() throws NamingException, NoSuchObjectException {
if (logger.isInfoEnabled()) {
logger.info("Unbinding RMI service from JNDI location [" + this.jndiName + "]");
}
this.jndiTemplate.unbind(this.jndiName);
// PortableRemoteObject.unexportObject(this.exportedObject);
}
}

181
fine-spring/src/main/java/com/fr/third/springframework/remoting/rmi/RemoteInvocationSerializingExporter.java

@ -1,181 +0,0 @@
/*
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fr.third.springframework.remoting.rmi;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.rmi.RemoteException;
import com.fr.third.springframework.beans.factory.InitializingBean;
import com.fr.third.springframework.remoting.support.RemoteInvocation;
import com.fr.third.springframework.remoting.support.RemoteInvocationBasedExporter;
import com.fr.third.springframework.remoting.support.RemoteInvocationResult;
import com.fr.third.springframework.util.Assert;
import com.fr.third.springframework.util.ClassUtils;
/**
* Abstract base class for remote service exporters that explicitly deserialize
* {@link com.fr.third.springframework.remoting.support.RemoteInvocation} objects and serialize
* {@link com.fr.third.springframework.remoting.support.RemoteInvocationResult} objects,
* for example Spring's HTTP invoker.
*
* <p>Provides template methods for {@code ObjectInputStream} and
* {@code ObjectOutputStream} handling.
*
* @author Juergen Hoeller
* @since 2.5.1
* @see java.io.ObjectInputStream
* @see java.io.ObjectOutputStream
* @see #doReadRemoteInvocation
* @see #doWriteRemoteInvocationResult
*/
public abstract class RemoteInvocationSerializingExporter extends RemoteInvocationBasedExporter
implements InitializingBean {
/**
* Default content type: "application/x-java-serialized-object"
*/
public static final String CONTENT_TYPE_SERIALIZED_OBJECT = "application/x-java-serialized-object";
private String contentType = CONTENT_TYPE_SERIALIZED_OBJECT;
private boolean acceptProxyClasses = true;
private Object proxy;
/**
* Specify the content type to use for sending remote invocation responses.
* <p>Default is "application/x-java-serialized-object".
*/
public void setContentType(String contentType) {
Assert.notNull(contentType, "'contentType' must not be null");
this.contentType = contentType;
}
/**
* Return the content type to use for sending remote invocation responses.
*/
public String getContentType() {
return this.contentType;
}
/**
* Set whether to accept deserialization of proxy classes.
* <p>Default is "true". May be deactivated as a security measure.
*/
public void setAcceptProxyClasses(boolean acceptProxyClasses) {
this.acceptProxyClasses = acceptProxyClasses;
}
/**
* Return whether to accept deserialization of proxy classes.
*/
public boolean isAcceptProxyClasses() {
return this.acceptProxyClasses;
}
@Override
public void afterPropertiesSet() {
prepare();
}
/**
* Initialize this service exporter.
*/
public void prepare() {
this.proxy = getProxyForService();
}
protected final Object getProxy() {
if (this.proxy == null) {
throw new IllegalStateException(ClassUtils.getShortName(getClass()) + " has not been initialized");
}
return this.proxy;
}
/**
* Create an ObjectInputStream for the given InputStream.
* <p>The default implementation creates a Spring {@link CodebaseAwareObjectInputStream}.
* @param is the InputStream to read from
* @return the new ObjectInputStream instance to use
* @throws java.io.IOException if creation of the ObjectInputStream failed
*/
protected ObjectInputStream createObjectInputStream(InputStream is) throws IOException {
return new CodebaseAwareObjectInputStream(is, getBeanClassLoader(), isAcceptProxyClasses());
}
/**
* Perform the actual reading of an invocation result object from the
* given ObjectInputStream.
* <p>The default implementation simply calls
* {@link java.io.ObjectInputStream#readObject()}.
* Can be overridden for deserialization of a custom wrapper object rather
* than the plain invocation, for example an encryption-aware holder.
* @param ois the ObjectInputStream to read from
* @return the RemoteInvocationResult object
* @throws java.io.IOException in case of I/O failure
* @throws ClassNotFoundException if case of a transferred class not
* being found in the local ClassLoader
*/
protected RemoteInvocation doReadRemoteInvocation(ObjectInputStream ois)
throws IOException, ClassNotFoundException {
Object obj = ois.readObject();
if (!(obj instanceof RemoteInvocation)) {
throw new RemoteException("Deserialized object needs to be assignable to type [" +
RemoteInvocation.class.getName() + "]: " + ClassUtils.getDescriptiveType(obj));
}
return (RemoteInvocation) obj;
}
/**
* Create an ObjectOutputStream for the given OutputStream.
* <p>The default implementation creates a plain
* {@link java.io.ObjectOutputStream}.
* @param os the OutputStream to write to
* @return the new ObjectOutputStream instance to use
* @throws java.io.IOException if creation of the ObjectOutputStream failed
*/
protected ObjectOutputStream createObjectOutputStream(OutputStream os) throws IOException {
return new ObjectOutputStream(os);
}
/**
* Perform the actual writing of the given invocation result object
* to the given ObjectOutputStream.
* <p>The default implementation simply calls
* {@link java.io.ObjectOutputStream#writeObject}.
* Can be overridden for serialization of a custom wrapper object rather
* than the plain invocation, for example an encryption-aware holder.
* @param result the RemoteInvocationResult object
* @param oos the ObjectOutputStream to write to
* @throws java.io.IOException if thrown by I/O methods
*/
protected void doWriteRemoteInvocationResult(RemoteInvocationResult result, ObjectOutputStream oos)
throws IOException {
oos.writeObject(result);
}
}

76
fine-spring/src/main/java/com/fr/third/springframework/remoting/rmi/RmiBasedExporter.java

@ -1,76 +0,0 @@
/*
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fr.third.springframework.remoting.rmi;
import java.lang.reflect.InvocationTargetException;
import java.rmi.Remote;
import com.fr.third.springframework.remoting.support.RemoteInvocation;
import com.fr.third.springframework.remoting.support.RemoteInvocationBasedExporter;
/**
* Convenient superclass for RMI-based remote exporters. Provides a facility
* to automatically wrap a given plain Java service object with an
* RmiInvocationWrapper, exposing the {@link RmiInvocationHandler} remote interface.
*
* <p>Using the RMI invoker mechanism, RMI communication operates at the {@link RmiInvocationHandler}
* level, sharing a common invoker stub for any number of services. Service interfaces are <i>not</i>
* required to extend {@code java.rmi.Remote} or declare {@code java.rmi.RemoteException}
* on all service methods. However, in and out parameters still have to be serializable.
*
* @author Juergen Hoeller
* @since 1.2.5
* @see RmiServiceExporter
* @see JndiRmiServiceExporter
*/
public abstract class RmiBasedExporter extends RemoteInvocationBasedExporter {
/**
* Determine the object to export: either the service object itself
* or a RmiInvocationWrapper in case of a non-RMI service object.
* @return the RMI object to export
* @see #setService
* @see #setServiceInterface
*/
protected Remote getObjectToExport() {
// determine remote object
if (getService() instanceof Remote &&
(getServiceInterface() == null || Remote.class.isAssignableFrom(getServiceInterface()))) {
// conventional RMI service
return (Remote) getService();
}
else {
// RMI invoker
if (logger.isDebugEnabled()) {
logger.debug("RMI service [" + getService() + "] is an RMI invoker");
}
return new RmiInvocationWrapper(getProxyForService(), this);
}
}
/**
* Redefined here to be visible to RmiInvocationWrapper.
* Simply delegates to the corresponding superclass method.
*/
@Override
protected Object invoke(RemoteInvocation invocation, Object targetObject)
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return super.invoke(invocation, targetObject);
}
}

416
fine-spring/src/main/java/com/fr/third/springframework/remoting/rmi/RmiClientInterceptor.java

@ -1,416 +0,0 @@
/*
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fr.third.springframework.remoting.rmi;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.RMIClientSocketFactory;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import com.fr.third.springframework.aop.support.AopUtils;
import com.fr.third.springframework.remoting.RemoteConnectFailureException;
import com.fr.third.springframework.remoting.RemoteInvocationFailureException;
import com.fr.third.springframework.remoting.RemoteLookupFailureException;
import com.fr.third.springframework.remoting.support.RemoteInvocationBasedAccessor;
import com.fr.third.springframework.remoting.support.RemoteInvocationUtils;
/**
* {@link org.aopalliance.intercept.MethodInterceptor} for accessing conventional
* RMI services or RMI invokers. The service URL must be a valid RMI URL
* (e.g. "rmi://localhost:1099/myservice").
*
* <p>RMI invokers work at the RmiInvocationHandler level, needing only one stub for
* any service. Service interfaces do not have to extend {@code java.rmi.Remote}
* or throw {@code java.rmi.RemoteException}. Spring's unchecked
* RemoteAccessException will be thrown on remote invocation failure.
* Of course, in and out parameters have to be serializable.
*
* <p>With conventional RMI services, this invoker is typically used with the RMI
* service interface. Alternatively, this invoker can also proxy a remote RMI service
* with a matching non-RMI business interface, i.e. an interface that mirrors the RMI
* service methods but does not declare RemoteExceptions. In the latter case,
* RemoteExceptions thrown by the RMI stub will automatically get converted to
* Spring's unchecked RemoteAccessException.
*
* @author Juergen Hoeller
* @since 29.09.2003
* @see RmiServiceExporter
* @see RmiProxyFactoryBean
* @see RmiInvocationHandler
* @see com.fr.third.springframework.remoting.RemoteAccessException
* @see java.rmi.RemoteException
* @see java.rmi.Remote
*/
public class RmiClientInterceptor extends RemoteInvocationBasedAccessor
implements MethodInterceptor {
private boolean lookupStubOnStartup = true;
private boolean cacheStub = true;
private boolean refreshStubOnConnectFailure = false;
private RMIClientSocketFactory registryClientSocketFactory;
private Remote cachedStub;
private final Object stubMonitor = new Object();
/**
* Set whether to look up the RMI stub on startup. Default is "true".
* <p>Can be turned off to allow for late start of the RMI server.
* In this case, the RMI stub will be fetched on first access.
* @see #setCacheStub
*/
public void setLookupStubOnStartup(boolean lookupStubOnStartup) {
this.lookupStubOnStartup = lookupStubOnStartup;
}
/**
* Set whether to cache the RMI stub once it has been located.
* Default is "true".
* <p>Can be turned off to allow for hot restart of the RMI server.
* In this case, the RMI stub will be fetched for each invocation.
* @see #setLookupStubOnStartup
*/
public void setCacheStub(boolean cacheStub) {
this.cacheStub = cacheStub;
}
/**
* Set whether to refresh the RMI stub on connect failure.
* Default is "false".
* <p>Can be turned on to allow for hot restart of the RMI server.
* If a cached RMI stub throws an RMI exception that indicates a
* remote connect failure, a fresh proxy will be fetched and the
* invocation will be retried.
* @see java.rmi.ConnectException
* @see java.rmi.ConnectIOException
* @see java.rmi.NoSuchObjectException
*/
public void setRefreshStubOnConnectFailure(boolean refreshStubOnConnectFailure) {
this.refreshStubOnConnectFailure = refreshStubOnConnectFailure;
}
/**
* Set a custom RMI client socket factory to use for accessing the RMI registry.
* @see java.rmi.server.RMIClientSocketFactory
* @see java.rmi.registry.LocateRegistry#getRegistry(String, int, RMIClientSocketFactory)
*/
public void setRegistryClientSocketFactory(RMIClientSocketFactory registryClientSocketFactory) {
this.registryClientSocketFactory = registryClientSocketFactory;
}
@Override
public void afterPropertiesSet() {
super.afterPropertiesSet();
prepare();
}
/**
* Fetches RMI stub on startup, if necessary.
* @throws RemoteLookupFailureException if RMI stub creation failed
* @see #setLookupStubOnStartup
* @see #lookupStub
*/
public void prepare() throws RemoteLookupFailureException {
// Cache RMI stub on initialization?
if (this.lookupStubOnStartup) {
Remote remoteObj = lookupStub();
if (logger.isDebugEnabled()) {
if (remoteObj instanceof RmiInvocationHandler) {
logger.debug("RMI stub [" + getServiceUrl() + "] is an RMI invoker");
}
else if (getServiceInterface() != null) {
boolean isImpl = getServiceInterface().isInstance(remoteObj);
logger.debug("Using service interface [" + getServiceInterface().getName() +
"] for RMI stub [" + getServiceUrl() + "] - " +
(!isImpl ? "not " : "") + "directly implemented");
}
}
if (this.cacheStub) {
this.cachedStub = remoteObj;
}
}
}
/**
* Create the RMI stub, typically by looking it up.
* <p>Called on interceptor initialization if "cacheStub" is "true";
* else called for each invocation by {@link #getStub()}.
* <p>The default implementation looks up the service URL via
* {@code java.rmi.Naming}. This can be overridden in subclasses.
* @return the RMI stub to store in this interceptor
* @throws RemoteLookupFailureException if RMI stub creation failed
* @see #setCacheStub
* @see java.rmi.Naming#lookup
*/
protected Remote lookupStub() throws RemoteLookupFailureException {
try {
Remote stub = null;
if (this.registryClientSocketFactory != null) {
// RMIClientSocketFactory specified for registry access.
// Unfortunately, due to RMI API limitations, this means
// that we need to parse the RMI URL ourselves and perform
// straight LocateRegistry.getRegistry/Registry.lookup calls.
URL url = new URL(null, getServiceUrl(), new DummyURLStreamHandler());
String protocol = url.getProtocol();
if (protocol != null && !"rmi".equals(protocol)) {
throw new MalformedURLException("Invalid URL scheme '" + protocol + "'");
}
String host = url.getHost();
int port = url.getPort();
String name = url.getPath();
if (name != null && name.startsWith("/")) {
name = name.substring(1);
}
Registry registry = LocateRegistry.getRegistry(host, port, this.registryClientSocketFactory);
stub = registry.lookup(name);
}
else {
// Can proceed with standard RMI lookup API...
stub = Naming.lookup(getServiceUrl());
}
if (logger.isDebugEnabled()) {
logger.debug("Located RMI stub with URL [" + getServiceUrl() + "]");
}
return stub;
}
catch (MalformedURLException ex) {
throw new RemoteLookupFailureException("Service URL [" + getServiceUrl() + "] is invalid", ex);
}
catch (NotBoundException ex) {
throw new RemoteLookupFailureException(
"Could not find RMI service [" + getServiceUrl() + "] in RMI registry", ex);
}
catch (RemoteException ex) {
throw new RemoteLookupFailureException("Lookup of RMI stub failed", ex);
}
}
/**
* Return the RMI stub to use. Called for each invocation.
* <p>The default implementation returns the stub created on initialization,
* if any. Else, it invokes {@link #lookupStub} to get a new stub for
* each invocation. This can be overridden in subclasses, for example in
* order to cache a stub for a given amount of time before recreating it,
* or to test the stub whether it is still alive.
* @return the RMI stub to use for an invocation
* @throws RemoteLookupFailureException if RMI stub creation failed
* @see #lookupStub
*/
protected Remote getStub() throws RemoteLookupFailureException {
if (!this.cacheStub || (this.lookupStubOnStartup && !this.refreshStubOnConnectFailure)) {
return (this.cachedStub != null ? this.cachedStub : lookupStub());
}
else {
synchronized (this.stubMonitor) {
if (this.cachedStub == null) {
this.cachedStub = lookupStub();
}
return this.cachedStub;
}
}
}
/**
* Fetches an RMI stub and delegates to {@code doInvoke}.
* If configured to refresh on connect failure, it will call
* {@link #refreshAndRetry} on corresponding RMI exceptions.
* @see #getStub
* @see #doInvoke(MethodInvocation, Remote)
* @see #refreshAndRetry
* @see java.rmi.ConnectException
* @see java.rmi.ConnectIOException
* @see java.rmi.NoSuchObjectException
*/
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
Remote stub = getStub();
try {
return doInvoke(invocation, stub);
}
catch (RemoteConnectFailureException ex) {
return handleRemoteConnectFailure(invocation, ex);
}
catch (RemoteException ex) {
if (isConnectFailure(ex)) {
return handleRemoteConnectFailure(invocation, ex);
}
else {
throw ex;
}
}
}
/**
* Determine whether the given RMI exception indicates a connect failure.
* <p>The default implementation delegates to
* {@link RmiClientInterceptorUtils#isConnectFailure}.
* @param ex the RMI exception to check
* @return whether the exception should be treated as connect failure
*/
protected boolean isConnectFailure(RemoteException ex) {
return RmiClientInterceptorUtils.isConnectFailure(ex);
}
/**
* Refresh the stub and retry the remote invocation if necessary.
* <p>If not configured to refresh on connect failure, this method
* simply rethrows the original exception.
* @param invocation the invocation that failed
* @param ex the exception raised on remote invocation
* @return the result value of the new invocation, if succeeded
* @throws Throwable an exception raised by the new invocation,
* if it failed as well
* @see #setRefreshStubOnConnectFailure
* @see #doInvoke
*/
private Object handleRemoteConnectFailure(MethodInvocation invocation, Exception ex) throws Throwable {
if (this.refreshStubOnConnectFailure) {
String msg = "Could not connect to RMI service [" + getServiceUrl() + "] - retrying";
if (logger.isDebugEnabled()) {
logger.warn(msg, ex);
}
else if (logger.isWarnEnabled()) {
logger.warn(msg);
}
return refreshAndRetry(invocation);
}
else {
throw ex;
}
}
/**
* Refresh the RMI stub and retry the given invocation.
* Called by invoke on connect failure.
* @param invocation the AOP method invocation
* @return the invocation result, if any
* @throws Throwable in case of invocation failure
* @see #invoke
*/
protected Object refreshAndRetry(MethodInvocation invocation) throws Throwable {
Remote freshStub = null;
synchronized (this.stubMonitor) {
this.cachedStub = null;
freshStub = lookupStub();
if (this.cacheStub) {
this.cachedStub = freshStub;
}
}
return doInvoke(invocation, freshStub);
}
/**
* Perform the given invocation on the given RMI stub.
* @param invocation the AOP method invocation
* @param stub the RMI stub to invoke
* @return the invocation result, if any
* @throws Throwable in case of invocation failure
*/
protected Object doInvoke(MethodInvocation invocation, Remote stub) throws Throwable {
if (stub instanceof RmiInvocationHandler) {
// RMI invoker
try {
return doInvoke(invocation, (RmiInvocationHandler) stub);
}
catch (RemoteException ex) {
throw RmiClientInterceptorUtils.convertRmiAccessException(
invocation.getMethod(), ex, isConnectFailure(ex), getServiceUrl());
}
catch (InvocationTargetException ex) {
Throwable exToThrow = ex.getTargetException();
RemoteInvocationUtils.fillInClientStackTraceIfPossible(exToThrow);
throw exToThrow;
}
catch (Throwable ex) {
throw new RemoteInvocationFailureException("Invocation of method [" + invocation.getMethod() +
"] failed in RMI service [" + getServiceUrl() + "]", ex);
}
}
else {
// traditional RMI stub
try {
return RmiClientInterceptorUtils.invokeRemoteMethod(invocation, stub);
}
catch (InvocationTargetException ex) {
Throwable targetEx = ex.getTargetException();
if (targetEx instanceof RemoteException) {
RemoteException rex = (RemoteException) targetEx;
throw RmiClientInterceptorUtils.convertRmiAccessException(
invocation.getMethod(), rex, isConnectFailure(rex), getServiceUrl());
}
else {
throw targetEx;
}
}
}
}
/**
* Apply the given AOP method invocation to the given {@link RmiInvocationHandler}.
* <p>The default implementation delegates to {@link #createRemoteInvocation}.
* @param methodInvocation the current AOP method invocation
* @param invocationHandler the RmiInvocationHandler to apply the invocation to
* @return the invocation result
* @throws RemoteException in case of communication errors
* @throws NoSuchMethodException if the method name could not be resolved
* @throws IllegalAccessException if the method could not be accessed
* @throws InvocationTargetException if the method invocation resulted in an exception
* @see com.fr.third.springframework.remoting.support.RemoteInvocation
*/
protected Object doInvoke(MethodInvocation methodInvocation, RmiInvocationHandler invocationHandler)
throws RemoteException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
if (AopUtils.isToStringMethod(methodInvocation.getMethod())) {
return "RMI invoker proxy for service URL [" + getServiceUrl() + "]";
}
return invocationHandler.invoke(createRemoteInvocation(methodInvocation));
}
/**
* Dummy URLStreamHandler that's just specified to suppress the standard
* {@code java.net.URL} URLStreamHandler lookup, to be able to
* use the standard URL class for parsing "rmi:..." URLs.
*/
private static class DummyURLStreamHandler extends URLStreamHandler {
@Override
protected URLConnection openConnection(URL url) throws IOException {
throw new UnsupportedOperationException();
}
}
}

193
fine-spring/src/main/java/com/fr/third/springframework/remoting/rmi/RmiClientInterceptorUtils.java

@ -1,193 +0,0 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fr.third.springframework.remoting.rmi;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.SocketException;
import java.rmi.ConnectException;
import java.rmi.ConnectIOException;
import java.rmi.NoSuchObjectException;
import java.rmi.RemoteException;
import java.rmi.StubNotFoundException;
import java.rmi.UnknownHostException;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.fr.third.springframework.remoting.RemoteAccessException;
import com.fr.third.springframework.remoting.RemoteConnectFailureException;
import com.fr.third.springframework.remoting.RemoteProxyFailureException;
import com.fr.third.springframework.util.ReflectionUtils;
/**
* Factored-out methods for performing invocations within an RMI client.
* Can handle both RMI and non-RMI service interfaces working on an RMI stub.
*
* <p>Note: This is an SPI class, not intended to be used by applications.
*
* @author Juergen Hoeller
* @since 1.1
*/
public abstract class RmiClientInterceptorUtils {
// 定制 本类中注释掉的内容,见
// https://code.fineres.com/projects/CORE/repos/base-third/commits/5b3f31597873b165b6a154393ee4ade942beec0a#fine-spring/src/com/fr/third/springframework/remoting/rmi/JndiRmiClientInterceptor.java
private static final Log logger = LogFactory.getLog(RmiClientInterceptorUtils.class);
/**
* Perform a raw method invocation on the given RMI stub,
* letting reflection exceptions through as-is.
* @param invocation the AOP MethodInvocation
* @param stub the RMI stub
* @return the invocation result, if any
* @throws InvocationTargetException if thrown by reflection
*/
public static Object invokeRemoteMethod(MethodInvocation invocation, Object stub)
throws InvocationTargetException {
Method method = invocation.getMethod();
try {
if (method.getDeclaringClass().isInstance(stub)) {
// directly implemented
return method.invoke(stub, invocation.getArguments());
}
else {
// not directly implemented
Method stubMethod = stub.getClass().getMethod(method.getName(), method.getParameterTypes());
return stubMethod.invoke(stub, invocation.getArguments());
}
}
catch (InvocationTargetException ex) {
throw ex;
}
catch (NoSuchMethodException ex) {
throw new RemoteProxyFailureException("No matching RMI stub method found for: " + method, ex);
}
catch (Throwable ex) {
throw new RemoteProxyFailureException("Invocation of RMI stub method failed: " + method, ex);
}
}
/**
* Wrap the given arbitrary exception that happened during remote access
* in either a RemoteException or a Spring RemoteAccessException (if the
* method signature does not support RemoteException).
* <p>Only call this for remote access exceptions, not for exceptions
* thrown by the target service itself!
* @param method the invoked method
* @param ex the exception that happened, to be used as cause for the
* RemoteAccessException or RemoteException
* @param message the message for the RemoteAccessException respectively
* RemoteException
* @return the exception to be thrown to the caller
*/
public static Exception convertRmiAccessException(Method method, Throwable ex, String message) {
if (logger.isDebugEnabled()) {
logger.debug(message, ex);
}
if (ReflectionUtils.declaresException(method, RemoteException.class)) {
return new RemoteException(message, ex);
}
else {
return new RemoteAccessException(message, ex);
}
}
/**
* Convert the given RemoteException that happened during remote access
* to Spring's RemoteAccessException if the method signature does not
* support RemoteException. Else, return the original RemoteException.
* @param method the invoked method
* @param ex the RemoteException that happened
* @param serviceName the name of the service (for debugging purposes)
* @return the exception to be thrown to the caller
*/
public static Exception convertRmiAccessException(Method method, RemoteException ex, String serviceName) {
return convertRmiAccessException(method, ex, isConnectFailure(ex), serviceName);
}
/**
* Convert the given RemoteException that happened during remote access
* to Spring's RemoteAccessException if the method signature does not
* support RemoteException. Else, return the original RemoteException.
* @param method the invoked method
* @param ex the RemoteException that happened
* @param isConnectFailure whether the given exception should be considered
* a connect failure
* @param serviceName the name of the service (for debugging purposes)
* @return the exception to be thrown to the caller
*/
public static Exception convertRmiAccessException(
Method method, RemoteException ex, boolean isConnectFailure, String serviceName) {
if (logger.isDebugEnabled()) {
logger.debug("Remote service [" + serviceName + "] threw exception", ex);
}
if (ReflectionUtils.declaresException(method, ex.getClass())) {
return ex;
}
else {
if (isConnectFailure) {
return new RemoteConnectFailureException("Could not connect to remote service [" + serviceName + "]", ex);
}
else {
return new RemoteAccessException("Could not access remote service [" + serviceName + "]", ex);
}
}
}
/**
* Determine whether the given RMI exception indicates a connect failure.
* <p>Treats RMI's ConnectException, ConnectIOException, UnknownHostException,
* NoSuchObjectException and StubNotFoundException as connect failure.
* @param ex the RMI exception to check
* @return whether the exception should be treated as connect failure
* @see java.rmi.ConnectException
* @see java.rmi.ConnectIOException
* @see java.rmi.UnknownHostException
* @see java.rmi.NoSuchObjectException
* @see java.rmi.StubNotFoundException
*/
public static boolean isConnectFailure(RemoteException ex) {
return (ex instanceof ConnectException || ex instanceof ConnectIOException ||
ex instanceof UnknownHostException || ex instanceof NoSuchObjectException ||
ex instanceof StubNotFoundException || ex.getCause() instanceof SocketException ||
isCorbaConnectFailure(ex.getCause()));
}
/**
* Check whether the given RMI exception root cause indicates a CORBA
* connection failure.
* <p>This is relevant on the IBM JVM, in particular for WebSphere EJB clients.
* <p>See the
* <a href="https://www.redbooks.ibm.com/Redbooks.nsf/RedbookAbstracts/tips0243.html">IBM website</code>
* for details.
* @param ex the RMI exception to check
*/
private static boolean isCorbaConnectFailure(Throwable ex) {
// return ((ex instanceof COMM_FAILURE || ex instanceof NO_RESPONSE) &&
// ((SystemException) ex).completed == CompletionStatus.COMPLETED_NO);
return (ex instanceof ConnectException || ex instanceof ConnectIOException ||
ex instanceof UnknownHostException || ex instanceof NoSuchObjectException ||
ex instanceof StubNotFoundException || ex.getCause() instanceof SocketException);
}
}

59
fine-spring/src/main/java/com/fr/third/springframework/remoting/rmi/RmiInvocationHandler.java

@ -1,59 +0,0 @@
/*
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fr.third.springframework.remoting.rmi;
import java.lang.reflect.InvocationTargetException;
import java.rmi.Remote;
import java.rmi.RemoteException;
import com.fr.third.springframework.remoting.support.RemoteInvocation;
/**
* Interface for RMI invocation handlers instances on the server,
* wrapping exported services. A client uses a stub implementing
* this interface to access such a service.
*
* <p>This is an SPI interface, not to be used directly by applications.
*
* @author Juergen Hoeller
* @since 14.05.2003
*/
public interface RmiInvocationHandler extends Remote {
/**
* Return the name of the target interface that this invoker operates on.
* @return the name of the target interface, or {@code null} if none
* @throws RemoteException in case of communication errors
* @see RmiServiceExporter#getServiceInterface()
*/
public String getTargetInterfaceName() throws RemoteException;
/**
* Apply the given invocation to the target object.
* <p>Called by
* {@link RmiClientInterceptor#doInvoke(org.aopalliance.intercept.MethodInvocation, RmiInvocationHandler)}.
* @param invocation object that encapsulates invocation parameters
* @return the object returned from the invoked method, if any
* @throws RemoteException in case of communication errors
* @throws NoSuchMethodException if the method name could not be resolved
* @throws IllegalAccessException if the method could not be accessed
* @throws InvocationTargetException if the method invocation resulted in an exception
*/
public Object invoke(RemoteInvocation invocation)
throws RemoteException, NoSuchMethodException, IllegalAccessException, InvocationTargetException;
}

77
fine-spring/src/main/java/com/fr/third/springframework/remoting/rmi/RmiInvocationWrapper.java

@ -1,77 +0,0 @@
/*
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fr.third.springframework.remoting.rmi;
import java.lang.reflect.InvocationTargetException;
import java.rmi.RemoteException;
import com.fr.third.springframework.remoting.support.RemoteInvocation;
import com.fr.third.springframework.util.Assert;
/**
* Server-side implementation of {@link RmiInvocationHandler}. An instance
* of this class exists for each remote object. Automatically created
* by {@link RmiServiceExporter} for non-RMI service implementations.
*
* <p>This is an SPI class, not to be used directly by applications.
*
* @author Juergen Hoeller
* @since 14.05.2003
* @see RmiServiceExporter
*/
class RmiInvocationWrapper implements RmiInvocationHandler {
private final Object wrappedObject;
private final RmiBasedExporter rmiExporter;
/**
* Create a new RmiInvocationWrapper for the given object
* @param wrappedObject the object to wrap with an RmiInvocationHandler
* @param rmiExporter the RMI exporter to handle the actual invocation
*/
public RmiInvocationWrapper(Object wrappedObject, RmiBasedExporter rmiExporter) {
Assert.notNull(wrappedObject, "Object to wrap is required");
Assert.notNull(rmiExporter, "RMI exporter is required");
this.wrappedObject = wrappedObject;
this.rmiExporter = rmiExporter;
}
/**
* Exposes the exporter's service interface, if any, as target interface.
* @see RmiBasedExporter#getServiceInterface()
*/
@Override
public String getTargetInterfaceName() {
Class<?> ifc = this.rmiExporter.getServiceInterface();
return (ifc != null ? ifc.getName() : null);
}
/**
* Delegates the actual invocation handling to the RMI exporter.
* @see RmiBasedExporter#invoke(org.springframework.remoting.support.RemoteInvocation, Object)
*/
@Override
public Object invoke(RemoteInvocation invocation)
throws RemoteException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return this.rmiExporter.invoke(invocation, this.wrappedObject);
}
}

91
fine-spring/src/main/java/com/fr/third/springframework/remoting/rmi/RmiProxyFactoryBean.java

@ -1,91 +0,0 @@
/*
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fr.third.springframework.remoting.rmi;
import com.fr.third.springframework.aop.framework.ProxyFactory;
import com.fr.third.springframework.beans.factory.BeanClassLoaderAware;
import com.fr.third.springframework.beans.factory.FactoryBean;
/**
* {@link FactoryBean} for RMI proxies, supporting both conventional RMI services
* and RMI invokers. Exposes the proxied service for use as a bean reference,
* using the specified service interface. Proxies will throw Spring's unchecked
* RemoteAccessException on remote invocation failure instead of RMI's RemoteException.
*
* <p>The service URL must be a valid RMI URL like "rmi://localhost:1099/myservice".
* RMI invokers work at the RmiInvocationHandler level, using the same invoker stub
* for any service. Service interfaces do not have to extend {@code java.rmi.Remote}
* or throw {@code java.rmi.RemoteException}. Of course, in and out parameters
* have to be serializable.
*
* <p>With conventional RMI services, this proxy factory is typically used with the
* RMI service interface. Alternatively, this factory can also proxy a remote RMI
* service with a matching non-RMI business interface, i.e. an interface that mirrors
* the RMI service methods but does not declare RemoteExceptions. In the latter case,
* RemoteExceptions thrown by the RMI stub will automatically get converted to
* Spring's unchecked RemoteAccessException.
*
* <p>The major advantage of RMI, compared to Hessian and Burlap, is serialization.
* Effectively, any serializable Java object can be transported without hassle.
* Hessian and Burlap have their own (de-)serialization mechanisms, but are
* HTTP-based and thus much easier to setup than RMI. Alternatively, consider
* Spring's HTTP invoker to combine Java serialization with HTTP-based transport.
*
* @author Juergen Hoeller
* @since 13.05.2003
* @see #setServiceInterface
* @see #setServiceUrl
* @see RmiClientInterceptor
* @see RmiServiceExporter
* @see java.rmi.Remote
* @see java.rmi.RemoteException
* @see com.fr.third.springframework.remoting.RemoteAccessException
* @see com.fr.third.springframework.remoting.caucho.HessianProxyFactoryBean
* @see com.fr.third.springframework.remoting.caucho.BurlapProxyFactoryBean
* @see com.fr.third.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean
*/
public class RmiProxyFactoryBean extends RmiClientInterceptor implements FactoryBean<Object>, BeanClassLoaderAware {
private Object serviceProxy;
@Override
public void afterPropertiesSet() {
super.afterPropertiesSet();
if (getServiceInterface() == null) {
throw new IllegalArgumentException("Property 'serviceInterface' is required");
}
this.serviceProxy = new ProxyFactory(getServiceInterface(), this).getProxy(getBeanClassLoader());
}
@Override
public Object getObject() {
return this.serviceProxy;
}
@Override
public Class<?> getObjectType() {
return getServiceInterface();
}
@Override
public boolean isSingleton() {
return true;
}
}

314
fine-spring/src/main/java/com/fr/third/springframework/remoting/rmi/RmiRegistryFactoryBean.java

@ -1,314 +0,0 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fr.third.springframework.remoting.rmi;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.RMIClientSocketFactory;
import java.rmi.server.RMIServerSocketFactory;
import java.rmi.server.UnicastRemoteObject;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.fr.third.springframework.beans.factory.DisposableBean;
import com.fr.third.springframework.beans.factory.FactoryBean;
import com.fr.third.springframework.beans.factory.InitializingBean;
/**
* {@link FactoryBean} that locates a {@link java.rmi.registry.Registry} and
* exposes it for bean references. Can also create a local RMI registry
* on the fly if none exists already.
*
* <p>Can be used to set up and pass around the actual Registry object to
* applications objects that need to work with RMI. One example for such an
* object that needs to work with RMI is Spring's {@link RmiServiceExporter},
* which either works with a passed-in Registry reference or falls back to
* the registry as specified by its local properties and defaults.
*
* <p>Also useful to enforce creation of a local RMI registry at a given port,
* for example for a JMX connector. If used in conjunction with
* {@link com.fr.third.springframework.jmx.support.ConnectorServerFactoryBean},
* it is recommended to mark the connector definition (ConnectorServerFactoryBean)
* as "depends-on" the registry definition (RmiRegistryFactoryBean),
* to guarantee starting up the registry first.
*
* <p>Note: The implementation of this class mirrors the corresponding logic
* in {@link RmiServiceExporter}, and also offers the same customization hooks.
* RmiServiceExporter implements its own registry lookup as a convenience:
* It is very common to simply rely on the registry defaults.
*
* @author Juergen Hoeller
* @since 1.2.3
* @see RmiServiceExporter#setRegistry
* @see com.fr.third.springframework.jmx.support.ConnectorServerFactoryBean
* @see java.rmi.registry.Registry
* @see java.rmi.registry.LocateRegistry
*/
public class RmiRegistryFactoryBean implements FactoryBean<Registry>, InitializingBean, DisposableBean {
protected final Log logger = LogFactory.getLog(getClass());
private String host;
private int port = Registry.REGISTRY_PORT;
private RMIClientSocketFactory clientSocketFactory;
private RMIServerSocketFactory serverSocketFactory;
private Registry registry;
private boolean alwaysCreate = false;
private boolean created = false;
/**
* Set the host of the registry for the exported RMI service,
* i.e. {@code rmi://HOST:port/name}
* <p>Default is localhost.
*/
public void setHost(String host) {
this.host = host;
}
/**
* Return the host of the registry for the exported RMI service.
*/
public String getHost() {
return this.host;
}
/**
* Set the port of the registry for the exported RMI service,
* i.e. {@code rmi://host:PORT/name}
* <p>Default is {@code Registry.REGISTRY_PORT} (1099).
*/
public void setPort(int port) {
this.port = port;
}
/**
* Return the port of the registry for the exported RMI service.
*/
public int getPort() {
return this.port;
}
/**
* Set a custom RMI client socket factory to use for the RMI registry.
* <p>If the given object also implements {@code java.rmi.server.RMIServerSocketFactory},
* it will automatically be registered as server socket factory too.
* @see #setServerSocketFactory
* @see java.rmi.server.RMIClientSocketFactory
* @see java.rmi.server.RMIServerSocketFactory
* @see java.rmi.registry.LocateRegistry#getRegistry(String, int, java.rmi.server.RMIClientSocketFactory)
*/
public void setClientSocketFactory(RMIClientSocketFactory clientSocketFactory) {
this.clientSocketFactory = clientSocketFactory;
}
/**
* Set a custom RMI server socket factory to use for the RMI registry.
* <p>Only needs to be specified when the client socket factory does not
* implement {@code java.rmi.server.RMIServerSocketFactory} already.
* @see #setClientSocketFactory
* @see java.rmi.server.RMIClientSocketFactory
* @see java.rmi.server.RMIServerSocketFactory
* @see java.rmi.registry.LocateRegistry#createRegistry(int, RMIClientSocketFactory, java.rmi.server.RMIServerSocketFactory)
*/
public void setServerSocketFactory(RMIServerSocketFactory serverSocketFactory) {
this.serverSocketFactory = serverSocketFactory;
}
/**
* Set whether to always create the registry in-process,
* not attempting to locate an existing registry at the specified port.
* <p>Default is "false". Switch this flag to "true" in order to avoid
* the overhead of locating an existing registry when you always
* intend to create a new registry in any case.
*/
public void setAlwaysCreate(boolean alwaysCreate) {
this.alwaysCreate = alwaysCreate;
}
@Override
public void afterPropertiesSet() throws Exception {
// Check socket factories for registry.
if (this.clientSocketFactory instanceof RMIServerSocketFactory) {
this.serverSocketFactory = (RMIServerSocketFactory) this.clientSocketFactory;
}
if ((this.clientSocketFactory != null && this.serverSocketFactory == null) ||
(this.clientSocketFactory == null && this.serverSocketFactory != null)) {
throw new IllegalArgumentException(
"Both RMIClientSocketFactory and RMIServerSocketFactory or none required");
}
// Fetch RMI registry to expose.
this.registry = getRegistry(this.host, this.port, this.clientSocketFactory, this.serverSocketFactory);
}
/**
* Locate or create the RMI registry.
* @param registryHost the registry host to use (if this is specified,
* no implicit creation of a RMI registry will happen)
* @param registryPort the registry port to use
* @param clientSocketFactory the RMI client socket factory for the registry (if any)
* @param serverSocketFactory the RMI server socket factory for the registry (if any)
* @return the RMI registry
* @throws java.rmi.RemoteException if the registry couldn't be located or created
*/
protected Registry getRegistry(String registryHost, int registryPort,
RMIClientSocketFactory clientSocketFactory, RMIServerSocketFactory serverSocketFactory)
throws RemoteException {
if (registryHost != null) {
// Host explicitly specified: only lookup possible.
if (logger.isInfoEnabled()) {
logger.info("Looking for RMI registry at port '" + registryPort + "' of host [" + registryHost + "]");
}
Registry reg = LocateRegistry.getRegistry(registryHost, registryPort, clientSocketFactory);
testRegistry(reg);
return reg;
}
else {
return getRegistry(registryPort, clientSocketFactory, serverSocketFactory);
}
}
/**
* Locate or create the RMI registry.
* @param registryPort the registry port to use
* @param clientSocketFactory the RMI client socket factory for the registry (if any)
* @param serverSocketFactory the RMI server socket factory for the registry (if any)
* @return the RMI registry
* @throws RemoteException if the registry couldn't be located or created
*/
protected Registry getRegistry(
int registryPort, RMIClientSocketFactory clientSocketFactory, RMIServerSocketFactory serverSocketFactory)
throws RemoteException {
if (clientSocketFactory != null) {
if (this.alwaysCreate) {
logger.info("Creating new RMI registry");
this.created = true;
return LocateRegistry.createRegistry(registryPort, clientSocketFactory, serverSocketFactory);
}
if (logger.isInfoEnabled()) {
logger.info("Looking for RMI registry at port '" + registryPort + "', using custom socket factory");
}
synchronized (LocateRegistry.class) {
try {
// Retrieve existing registry.
Registry reg = LocateRegistry.getRegistry(null, registryPort, clientSocketFactory);
testRegistry(reg);
return reg;
}
catch (RemoteException ex) {
logger.debug("RMI registry access threw exception", ex);
logger.info("Could not detect RMI registry - creating new one");
// Assume no registry found -> create new one.
this.created = true;
return LocateRegistry.createRegistry(registryPort, clientSocketFactory, serverSocketFactory);
}
}
}
else {
return getRegistry(registryPort);
}
}
/**
* Locate or create the RMI registry.
* @param registryPort the registry port to use
* @return the RMI registry
* @throws RemoteException if the registry couldn't be located or created
*/
protected Registry getRegistry(int registryPort) throws RemoteException {
if (this.alwaysCreate) {
logger.info("Creating new RMI registry");
this.created = true;
return LocateRegistry.createRegistry(registryPort);
}
if (logger.isInfoEnabled()) {
logger.info("Looking for RMI registry at port '" + registryPort + "'");
}
synchronized (LocateRegistry.class) {
try {
// Retrieve existing registry.
Registry reg = LocateRegistry.getRegistry(registryPort);
testRegistry(reg);
return reg;
}
catch (RemoteException ex) {
logger.debug("RMI registry access threw exception", ex);
logger.info("Could not detect RMI registry - creating new one");
// Assume no registry found -> create new one.
this.created = true;
return LocateRegistry.createRegistry(registryPort);
}
}
}
/**
* Test the given RMI registry, calling some operation on it to
* check whether it is still active.
* <p>Default implementation calls {@code Registry.list()}.
* @param registry the RMI registry to test
* @throws RemoteException if thrown by registry methods
* @see java.rmi.registry.Registry#list()
*/
protected void testRegistry(Registry registry) throws RemoteException {
registry.list();
}
@Override
public Registry getObject() throws Exception {
return this.registry;
}
@Override
public Class<? extends Registry> getObjectType() {
return (this.registry != null ? this.registry.getClass() : Registry.class);
}
@Override
public boolean isSingleton() {
return true;
}
/**
* Unexport the RMI registry on bean factory shutdown,
* provided that this bean actually created a registry.
*/
@Override
public void destroy() throws RemoteException {
if (this.created) {
logger.info("Unexporting RMI registry");
UnicastRemoteObject.unexportObject(this.registry, true);
}
}
}

462
fine-spring/src/main/java/com/fr/third/springframework/remoting/rmi/RmiServiceExporter.java

@ -1,462 +0,0 @@
/*
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fr.third.springframework.remoting.rmi;
import java.rmi.AlreadyBoundException;
import java.rmi.NoSuchObjectException;
import java.rmi.NotBoundException;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.RMIClientSocketFactory;
import java.rmi.server.RMIServerSocketFactory;
import java.rmi.server.UnicastRemoteObject;
import com.fr.third.springframework.beans.factory.DisposableBean;
import com.fr.third.springframework.beans.factory.InitializingBean;
/**
* RMI exporter that exposes the specified service as RMI object with the specified name.
* Such services can be accessed via plain RMI or via {@link RmiProxyFactoryBean}.
* Also supports exposing any non-RMI service via RMI invokers, to be accessed via
* {@link RmiClientInterceptor} / {@link RmiProxyFactoryBean}'s automatic detection
* of such invokers.
*
* <p>With an RMI invoker, RMI communication works on the {@link RmiInvocationHandler}
* level, needing only one stub for any service. Service interfaces do not have to
* extend {@code java.rmi.Remote} or throw {@code java.rmi.RemoteException}
* on all methods, but in and out parameters have to be serializable.
*
* <p>The major advantage of RMI, compared to Hessian and Burlap, is serialization.
* Effectively, any serializable Java object can be transported without hassle.
* Hessian and Burlap have their own (de-)serialization mechanisms, but are
* HTTP-based and thus much easier to setup than RMI. Alternatively, consider
* Spring's HTTP invoker to combine Java serialization with HTTP-based transport.
*
* <p>Note: RMI makes a best-effort attempt to obtain the fully qualified host name.
* If one cannot be determined, it will fall back and use the IP address. Depending
* on your network configuration, in some cases it will resolve the IP to the loopback
* address. To ensure that RMI will use the host name bound to the correct network
* interface, you should pass the {@code java.rmi.server.hostname} property to the
* JVM that will export the registry and/or the service using the "-D" JVM argument.
* For example: {@code -Djava.rmi.server.hostname=myserver.com}
*
* @author Juergen Hoeller
* @since 13.05.2003
* @see RmiClientInterceptor
* @see RmiProxyFactoryBean
* @see java.rmi.Remote
* @see java.rmi.RemoteException
* @see com.fr.third.springframework.remoting.caucho.HessianServiceExporter
* @see com.fr.third.springframework.remoting.caucho.BurlapServiceExporter
* @see com.fr.third.springframework.remoting.httpinvoker.HttpInvokerServiceExporter
*/
public class RmiServiceExporter extends RmiBasedExporter implements InitializingBean, DisposableBean {
private String serviceName;
private int servicePort = 0; // anonymous port
private RMIClientSocketFactory clientSocketFactory;
private RMIServerSocketFactory serverSocketFactory;
private Registry registry;
private String registryHost;
private int registryPort = Registry.REGISTRY_PORT;
private RMIClientSocketFactory registryClientSocketFactory;
private RMIServerSocketFactory registryServerSocketFactory;
private boolean alwaysCreateRegistry = false;
private boolean replaceExistingBinding = true;
private Remote exportedObject;
private boolean createdRegistry = false;
/**
* Set the name of the exported RMI service,
* i.e. {@code rmi://host:port/NAME}
*/
public void setServiceName(String serviceName) {
this.serviceName = serviceName;
}
/**
* Set the port that the exported RMI service will use.
* <p>Default is 0 (anonymous port).
*/
public void setServicePort(int servicePort) {
this.servicePort = servicePort;
}
/**
* Set a custom RMI client socket factory to use for exporting the service.
* <p>If the given object also implements {@code java.rmi.server.RMIServerSocketFactory},
* it will automatically be registered as server socket factory too.
* @see #setServerSocketFactory
* @see java.rmi.server.RMIClientSocketFactory
* @see java.rmi.server.RMIServerSocketFactory
* @see UnicastRemoteObject#exportObject(Remote, int, RMIClientSocketFactory, RMIServerSocketFactory)
*/
public void setClientSocketFactory(RMIClientSocketFactory clientSocketFactory) {
this.clientSocketFactory = clientSocketFactory;
}
/**
* Set a custom RMI server socket factory to use for exporting the service.
* <p>Only needs to be specified when the client socket factory does not
* implement {@code java.rmi.server.RMIServerSocketFactory} already.
* @see #setClientSocketFactory
* @see java.rmi.server.RMIClientSocketFactory
* @see java.rmi.server.RMIServerSocketFactory
* @see UnicastRemoteObject#exportObject(Remote, int, RMIClientSocketFactory, RMIServerSocketFactory)
*/
public void setServerSocketFactory(RMIServerSocketFactory serverSocketFactory) {
this.serverSocketFactory = serverSocketFactory;
}
/**
* Specify the RMI registry to register the exported service with.
* Typically used in combination with RmiRegistryFactoryBean.
* <p>Alternatively, you can specify all registry properties locally.
* This exporter will then try to locate the specified registry,
* automatically creating a new local one if appropriate.
* <p>Default is a local registry at the default port (1099),
* created on the fly if necessary.
* @see RmiRegistryFactoryBean
* @see #setRegistryHost
* @see #setRegistryPort
* @see #setRegistryClientSocketFactory
* @see #setRegistryServerSocketFactory
*/
public void setRegistry(Registry registry) {
this.registry = registry;
}
/**
* Set the host of the registry for the exported RMI service,
* i.e. {@code rmi://HOST:port/name}
* <p>Default is localhost.
*/
public void setRegistryHost(String registryHost) {
this.registryHost = registryHost;
}
/**
* Set the port of the registry for the exported RMI service,
* i.e. {@code rmi://host:PORT/name}
* <p>Default is {@code Registry.REGISTRY_PORT} (1099).
* @see java.rmi.registry.Registry#REGISTRY_PORT
*/
public void setRegistryPort(int registryPort) {
this.registryPort = registryPort;
}
/**
* Set a custom RMI client socket factory to use for the RMI registry.
* <p>If the given object also implements {@code java.rmi.server.RMIServerSocketFactory},
* it will automatically be registered as server socket factory too.
* @see #setRegistryServerSocketFactory
* @see java.rmi.server.RMIClientSocketFactory
* @see java.rmi.server.RMIServerSocketFactory
* @see LocateRegistry#getRegistry(String, int, RMIClientSocketFactory)
*/
public void setRegistryClientSocketFactory(RMIClientSocketFactory registryClientSocketFactory) {
this.registryClientSocketFactory = registryClientSocketFactory;
}
/**
* Set a custom RMI server socket factory to use for the RMI registry.
* <p>Only needs to be specified when the client socket factory does not
* implement {@code java.rmi.server.RMIServerSocketFactory} already.
* @see #setRegistryClientSocketFactory
* @see java.rmi.server.RMIClientSocketFactory
* @see java.rmi.server.RMIServerSocketFactory
* @see LocateRegistry#createRegistry(int, RMIClientSocketFactory, RMIServerSocketFactory)
*/
public void setRegistryServerSocketFactory(RMIServerSocketFactory registryServerSocketFactory) {
this.registryServerSocketFactory = registryServerSocketFactory;
}
/**
* Set whether to always create the registry in-process,
* not attempting to locate an existing registry at the specified port.
* <p>Default is "false". Switch this flag to "true" in order to avoid
* the overhead of locating an existing registry when you always
* intend to create a new registry in any case.
*/
public void setAlwaysCreateRegistry(boolean alwaysCreateRegistry) {
this.alwaysCreateRegistry = alwaysCreateRegistry;
}
/**
* Set whether to replace an existing binding in the RMI registry,
* that is, whether to simply override an existing binding with the
* specified service in case of a naming conflict in the registry.
* <p>Default is "true", assuming that an existing binding for this
* exporter's service name is an accidental leftover from a previous
* execution. Switch this to "false" to make the exporter fail in such
* a scenario, indicating that there was already an RMI object bound.
*/
public void setReplaceExistingBinding(boolean replaceExistingBinding) {
this.replaceExistingBinding = replaceExistingBinding;
}
@Override
public void afterPropertiesSet() throws RemoteException {
prepare();
}
/**
* Initialize this service exporter, registering the service as RMI object.
* <p>Creates an RMI registry on the specified port if none exists.
* @throws RemoteException if service registration failed
*/
public void prepare() throws RemoteException {
checkService();
if (this.serviceName == null) {
throw new IllegalArgumentException("Property 'serviceName' is required");
}
// Check socket factories for exported object.
if (this.clientSocketFactory instanceof RMIServerSocketFactory) {
this.serverSocketFactory = (RMIServerSocketFactory) this.clientSocketFactory;
}
if ((this.clientSocketFactory != null && this.serverSocketFactory == null) ||
(this.clientSocketFactory == null && this.serverSocketFactory != null)) {
throw new IllegalArgumentException(
"Both RMIClientSocketFactory and RMIServerSocketFactory or none required");
}
// Check socket factories for RMI registry.
if (this.registryClientSocketFactory instanceof RMIServerSocketFactory) {
this.registryServerSocketFactory = (RMIServerSocketFactory) this.registryClientSocketFactory;
}
if (this.registryClientSocketFactory == null && this.registryServerSocketFactory != null) {
throw new IllegalArgumentException(
"RMIServerSocketFactory without RMIClientSocketFactory for registry not supported");
}
this.createdRegistry = false;
// Determine RMI registry to use.
if (this.registry == null) {
this.registry = getRegistry(this.registryHost, this.registryPort,
this.registryClientSocketFactory, this.registryServerSocketFactory);
this.createdRegistry = true;
}
// Initialize and cache exported object.
this.exportedObject = getObjectToExport();
if (logger.isInfoEnabled()) {
logger.info("Binding service '" + this.serviceName + "' to RMI registry: " + this.registry);
}
// Export RMI object.
if (this.clientSocketFactory != null) {
UnicastRemoteObject.exportObject(
this.exportedObject, this.servicePort, this.clientSocketFactory, this.serverSocketFactory);
}
else {
UnicastRemoteObject.exportObject(this.exportedObject, this.servicePort);
}
// Bind RMI object to registry.
try {
if (this.replaceExistingBinding) {
this.registry.rebind(this.serviceName, this.exportedObject);
}
else {
this.registry.bind(this.serviceName, this.exportedObject);
}
}
catch (AlreadyBoundException ex) {
// Already an RMI object bound for the specified service name...
unexportObjectSilently();
throw new IllegalStateException(
"Already an RMI object bound for name '" + this.serviceName + "': " + ex.toString());
}
catch (RemoteException ex) {
// Registry binding failed: let's unexport the RMI object as well.
unexportObjectSilently();
throw ex;
}
}
/**
* Locate or create the RMI registry for this exporter.
* @param registryHost the registry host to use (if this is specified,
* no implicit creation of a RMI registry will happen)
* @param registryPort the registry port to use
* @param clientSocketFactory the RMI client socket factory for the registry (if any)
* @param serverSocketFactory the RMI server socket factory for the registry (if any)
* @return the RMI registry
* @throws RemoteException if the registry couldn't be located or created
*/
protected Registry getRegistry(String registryHost, int registryPort,
RMIClientSocketFactory clientSocketFactory, RMIServerSocketFactory serverSocketFactory)
throws RemoteException {
if (registryHost != null) {
// Host explicitly specified: only lookup possible.
if (logger.isInfoEnabled()) {
logger.info("Looking for RMI registry at port '" + registryPort + "' of host [" + registryHost + "]");
}
Registry reg = LocateRegistry.getRegistry(registryHost, registryPort, clientSocketFactory);
testRegistry(reg);
return reg;
}
else {
return getRegistry(registryPort, clientSocketFactory, serverSocketFactory);
}
}
/**
* Locate or create the RMI registry for this exporter.
* @param registryPort the registry port to use
* @param clientSocketFactory the RMI client socket factory for the registry (if any)
* @param serverSocketFactory the RMI server socket factory for the registry (if any)
* @return the RMI registry
* @throws RemoteException if the registry couldn't be located or created
*/
protected Registry getRegistry(
int registryPort, RMIClientSocketFactory clientSocketFactory, RMIServerSocketFactory serverSocketFactory)
throws RemoteException {
if (clientSocketFactory != null) {
if (this.alwaysCreateRegistry) {
logger.info("Creating new RMI registry");
return LocateRegistry.createRegistry(registryPort, clientSocketFactory, serverSocketFactory);
}
if (logger.isInfoEnabled()) {
logger.info("Looking for RMI registry at port '" + registryPort + "', using custom socket factory");
}
synchronized (LocateRegistry.class) {
try {
// Retrieve existing registry.
Registry reg = LocateRegistry.getRegistry(null, registryPort, clientSocketFactory);
testRegistry(reg);
return reg;
}
catch (RemoteException ex) {
logger.debug("RMI registry access threw exception", ex);
logger.info("Could not detect RMI registry - creating new one");
// Assume no registry found -> create new one.
return LocateRegistry.createRegistry(registryPort, clientSocketFactory, serverSocketFactory);
}
}
}
else {
return getRegistry(registryPort);
}
}
/**
* Locate or create the RMI registry for this exporter.
* @param registryPort the registry port to use
* @return the RMI registry
* @throws RemoteException if the registry couldn't be located or created
*/
protected Registry getRegistry(int registryPort) throws RemoteException {
if (this.alwaysCreateRegistry) {
logger.info("Creating new RMI registry");
return LocateRegistry.createRegistry(registryPort);
}
if (logger.isInfoEnabled()) {
logger.info("Looking for RMI registry at port '" + registryPort + "'");
}
synchronized (LocateRegistry.class) {
try {
// Retrieve existing registry.
Registry reg = LocateRegistry.getRegistry(registryPort);
testRegistry(reg);
return reg;
}
catch (RemoteException ex) {
logger.debug("RMI registry access threw exception", ex);
logger.info("Could not detect RMI registry - creating new one");
// Assume no registry found -> create new one.
return LocateRegistry.createRegistry(registryPort);
}
}
}
/**
* Test the given RMI registry, calling some operation on it to
* check whether it is still active.
* <p>Default implementation calls {@code Registry.list()}.
* @param registry the RMI registry to test
* @throws RemoteException if thrown by registry methods
* @see java.rmi.registry.Registry#list()
*/
protected void testRegistry(Registry registry) throws RemoteException {
registry.list();
}
/**
* Unbind the RMI service from the registry on bean factory shutdown.
*/
@Override
public void destroy() throws RemoteException {
if (logger.isInfoEnabled()) {
logger.info("Unbinding RMI service '" + this.serviceName +
"' from registry" + (this.createdRegistry ? (" at port '" + this.registryPort + "'") : ""));
}
try {
this.registry.unbind(this.serviceName);
}
catch (NotBoundException ex) {
if (logger.isWarnEnabled()) {
logger.warn("RMI service '" + this.serviceName + "' is not bound to registry" +
(this.createdRegistry ? (" at port '" + this.registryPort + "' anymore") : ""), ex);
}
}
finally {
unexportObjectSilently();
}
}
/**
* Unexport the registered RMI object, logging any exception that arises.
*/
private void unexportObjectSilently() {
try {
UnicastRemoteObject.unexportObject(this.exportedObject, true);
}
catch (NoSuchObjectException ex) {
if (logger.isWarnEnabled()) {
logger.warn("RMI object for service '" + this.serviceName + "' is not exported anymore", ex);
}
}
}
}

6
fine-spring/src/main/java/com/fr/third/springframework/remoting/rmi/package-info.java

@ -1,6 +0,0 @@
/**
* Remoting classes for conventional RMI and transparent remoting via
* RMI invokers. Provides a proxy factory for accessing RMI services,
* and an exporter for making beans available to RMI clients.
*/
package com.fr.third.springframework.remoting.rmi;
Loading…
Cancel
Save