Zobrazují se příspěvky se štítkemglassfish. Zobrazit všechny příspěvky
Zobrazují se příspěvky se štítkemglassfish. Zobrazit všechny příspěvky

středa 5. června 2013

Glassfish 3.1.2.2 bug GRIZZLY-1375 a GRIZZLY-1385

V glassfishi novějším než verze 3.0.1 se objevuje chyba v grizzlym. Ta se projeví, při volání webové služby se zabezpečením, následujícím výpisem do serverového logu:
 WSITPVD0035: Error in Verifying Security in Inbound Message.  
 com.sun.xml.wss.impl.XWSSecurityRuntimeException: WSS1601: Security Requirements not met - Transport binding configured in policy but incoming message was not SSL enabled  
      at com.sun.xml.wss.impl.policy.verifier.MessagePolicyVerifier.verifyPolicy(MessagePolicyVerifier.java:125)  

Chyba je již od grizzlyho verze 1.9.55 vyřešena. Ovšem tato verze zatím není z update centra glassfishe dostupná.
Osvědčil se mi však následující postup s použitím toho času nejnovější verze Glassfish 3.1.2.2:
  1. Stáhnout si grizzly-utils-1.9.57.jar
  2. Stáhnout si grizzly-lzma-1.9.57.jar 
  3. Stažené soubory umístit do adresáře glassfish/modules
  4. Přihlásit se telnetem na localhost 6666. Pokud tuta volba není v GF ještě povolena, lze postupovat podle kapitoly 10.4.1 v tomto dokumentu
  5. Zadat příkaz lb grizzly. Ve výpisu budou řádky podobné těmto:
      224|Resolved   |    1|grizzly-lzma (1.9.50)
     265|Resolved   |    1|grizzly-utils (1.9.50)
  6. postupně zadat příkaz uninstall s parametrem id (první sloupec předchozího výpisu). V tomto případě
    uninstall 224
    uninstall 265
  7. Instalace novějších verzí:
    install file:../../../modules/grizzly-lzma-1.9.57.jar
    install file:../../../modules/grizzly-utils-1.9.57.jar
  8. Nyní je možné odstranit původní soubory bundlů
    rm glassfish/modules/grizzly-lzma.jar
    rm glassfish/modules/grizzly-utils.jar
Díky této opravě je možné narazit na další chybu v GF. Problémem je volání metody javax.xml.ws.WebServiceContext.getUserPrincipal(). Stejná data lze však získat i voláním javax.xml.ws.WebServiceContext.getMessageContext().get("CLIENT_SUBJECT"). Například uživatelské jméno lze získat následovně:
 javax.security.auth.Subject subject = (javax.security.auth.Subject)wsContext.getMessageContext().get("CLIENT_SUBJECT");  
       Set privateCredentials = subject.getPrivateCredentials();  
       String userName;  
       for(Object credential : privateCredentials){  
         if(credential instanceof com.sun.enterprise.security.auth.login.common.PasswordCredential) userName = ((com.sun.enterprise.security.auth.login.common.PasswordCredential)credential).getUser();  
       }  

Drobný tip k update centru nakonec: Možná se snažíte spustit update center a ten píše hlášku:
 You are running on a 64 bit Linux distribution and the 32 bit Linux  
 compatibility libraries do not appear to be installed. In order to use  
 the Update Center tools you must install the 32 bit compatibility libraries.  
 On Ubuntu (and possibly other Debian based systems) please install the  
 ia32-libs package. On RedHat 4 (and other RPM based systems), you may  
 need to add multiple 'compat' runtime library packages. Please see the  
 Update Center Release Notes for more information  
Pokud jste již ia32-libs nainstalovali a nepřišla žádná změna, pak vězte, že je třeba ještě nainstalovat libjpeg62:i386. Např. příkazem sudo apt-get install libjpeg62:i386

středa 3. dubna 2013

Glassfish JMS broker perzistující zprávy do Sybase ASE

Co budeme potřebovat:
  1. Oracle Glassfish 3.1.2.2 Dále je předpokládáno umístění v ~/glassfish3122
  2. Sybase Adaptive Server Enterprise 15.5
  3. JMS broker (integrovaný v Glassfishi)
  4. JDBC konektor pro Sybase ASE - jConnect 7.0.7
Postup:
1) Ve webové administraci serveru Glassfish otevřeme Configurations->server-config->Java Message Service. JMS Service Type nastavíme na hodnotu LOCAL. Poté v Additional Properties postupně nastavíme následující:
 <property name="imq.persist.store" value="jdbc"></property>  
     <property name="imq.persist.jdbc.sybase.driver" value="com.sybase.jdbc4.jdbc.SybDriver"></property>  
     <property name="imq.persist.jdbc.sybase.user" value="db_user"></property>  
     <property name="imq.persist.jdbc.sybase.password" value="db_user_passwd"></property>  
     <property name="imq.persist.jdbc.dbVendor" value="sybase"></property>  
     <property name="imq.brokerid" value="testBroker"></property>  
     <property name="imq.autocreate.reaptime" value="1"></property>  
     <property name="imq.instanceconfig.version" value="300"></property>  
     <property name="imq.jmsra.managed" value="true"></property>  
     <property name="imq.persist.jdbc.sybase.closedburl" value="jdbc:sybase:Tds:IPAddress:port/database"></property>  
     <property name="imq.persist.jdbc.sybase.opendburl" value="jdbc:sybase:Tds:IPAddress:port/database"></property>  
 Toto je samozřejmě možné zadat i v souboru config/domain.xml příslušné domény.
Pokud se rozhodnete namísto com.sybase.jdbc4.jdbc.SybDriver použít com.sybase.jdbc4.jdbc.SybDataSource nejspíš vás v logu bude čekat tato chyba:
 ERROR [B3000]: Could not open persistent message store:  
 com.sun.messaging.jmq.jmsserver.util.BrokerException: [B3026]: Failed to get connection to jdbc:sybase:Tds:IPAddress:2030/database  
      at com.sun.messaging.jmq.jmsserver.persist.jdbc.comm.CommDBManager.newConnection(CommDBManager.java:796)  
      at com.sun.messaging.jmq.jmsserver.persist.jdbc.comm.CommDBManager.getNewConnection(CommDBManager.java:757)  
      at com.sun.messaging.jmq.jmsserver.persist.jdbc.comm.DBConnectionPool.createConnection(DBConnectionPool.java:483)  
      at com.sun.messaging.jmq.jmsserver.persist.jdbc.comm.DBConnectionPool.<init>(DBConnectionPool.java:352)  
      at com.sun.messaging.jmq.jmsserver.persist.jdbc.comm.DBConnectionPool.<init>(DBConnectionPool.java:233)  
      at com.sun.messaging.jmq.jmsserver.persist.jdbc.DBManager.getDBManager(DBManager.java:184)  
      at com.sun.messaging.jmq.jmsserver.persist.jdbc.JDBCStore.<init>(JDBCStore.java:112)  
      at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)  
      at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)  
      at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)  
      at java.lang.reflect.Constructor.newInstance(Constructor.java:525)  
      at java.lang.Class.newInstance0(Class.java:372)  
      at java.lang.Class.newInstance(Class.java:325)  
      at com.sun.messaging.jmq.jmsserver.persist.StoreManager.getStore(StoreManager.java:169)  
      at com.sun.messaging.jmq.jmsserver.Globals.getStore(Globals.java:995)  
      at com.sun.messaging.jmq.jmsserver.Broker._start(Broker.java:955)  
      at com.sun.messaging.jmq.jmsserver.Broker.start(Broker.java:456)  
      at com.sun.messaging.jmq.jmsserver.Broker.main(Broker.java:2151)  
 Caused by: java.sql.SQLException: JZ0PN: Specified port number of -1 was out of range. Port numbers must meet the following conditions: 0 <= portNumber <= 65535  
      at com.sybase.jdbc4.jdbc.SybConnection.getAllExceptions(SybConnection.java:2780)  
      at com.sybase.jdbc4.jdbc.SybConnection.handleSQLE(SybConnection.java:2648)  
      at com.sybase.jdbc4.jdbc.SybConnection.tryLogin(SybConnection.java:479)  
      at com.sybase.jdbc4.jdbc.SybConnection.handleHAFailover(SybConnection.java:3109)  
      at com.sybase.jdbc4.jdbc.SybConnection.<init>(SybConnection.java:328)  
      at com.sybase.jdbc4.jdbc.SybDriver.createConnection(SybDriver.java:681)  
      at com.sybase.jdbc4.jdbc.SybDriver.connect(SybDriver.java:620)  
      at com.sybase.jdbc4.jdbc.SybDriver.connect(SybDriver.java:653)  
      at com.sybase.jdbc4.jdbc.SybDataSource.getConnection(SybDataSource.java:320)  
      at com.sun.messaging.jmq.jmsserver.persist.jdbc.comm.CommDBManager.newConnection(CommDBManager.java:782)  
      ... 17 more|#]  
Pokud se budete snažit použít některý ze starších ovladačů od Sybase, například verze 6.0, bude v logu chyba následující:
 Local broker:ERROR [B3000]: Could not open persistent message store:  
 com.sun.messaging.jmq.jmsserver.util.BrokerException: Failed to open persistent store.  
      at com.sun.messaging.jmq.jmsserver.persist.StoreManager.getStore(StoreManager.java:219)  
      at com.sun.messaging.jmq.jmsserver.Globals.getStore(Globals.java:995)  
      at com.sun.messaging.jmq.jmsserver.Broker._start(Broker.java:955)  
      at com.sun.messaging.jmq.jmsserver.Broker.start(Broker.java:456)  
      at com.sun.messaging.jmq.jmsserver.Broker.main(Broker.java:2151)  
 Caused by: com.sybase.jdbc3.utils.UnimplementedOperationException: The method com.sybase.jdbc3.jdbc.SybDatabaseMetaData.getSQLStateType() has not been completed and should not be called.  
      at com.sybase.jdbc3.jdbc.ErrorMessage.raiseRuntimeException(ErrorMessage.java:950)  
      at com.sybase.jdbc3.utils.Debug.notImplemented(Debug.java:387)  
      at com.sybase.jdbc3.jdbc.SybDatabaseMetaData.getSQLStateType(SybDatabaseMetaData.java:2261)  
      at com.sun.messaging.jmq.jmsserver.persist.jdbc.comm.CommDBManager.initDBMetaData(CommDBManager.java:177)  
      at com.sun.messaging.jmq.jmsserver.persist.jdbc.DBManager.getDBManager(DBManager.java:185)  
      at com.sun.messaging.jmq.jmsserver.persist.jdbc.JDBCStore.<init>(JDBCStore.java:112)  
      at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)  
      at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)  
      at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)  
      at java.lang.reflect.Constructor.newInstance(Constructor.java:525)  
      at java.lang.Class.newInstance0(Class.java:372)  
      at java.lang.Class.newInstance(Class.java:325)  
      at com.sun.messaging.jmq.jmsserver.persist.StoreManager.getStore(StoreManager.java:169)  
      ... 4 more|#]  

2) Abychom mohli používat JDBC ovladač pro Sybase ASE uvedený v kroku 1, musíme o něm dát JMS brokerovi vědět. To uděláme v souboru ~/glassfish3122/mq/etc/imqenv.conf přidáním řádku s cestou k ovladači: IMQ_DEFAULT_EXT_JARS=~/glassfish3122/glassfish/lib/jconn4-7.0.7.jar V uvedeném umístění samozřejmě musí tento soubor existovat.
Pokud cesta k ovladači nebude uvedena správně, objeví se v logu chyba:
 Local broker: ERROR [B3000]: Could not open persistent message store:  
 com.sun.messaging.jmq.jmsserver.util.BrokerException: [B3024]: Failed to load JDBC driver: com.sybase.jdbc4.jdbc.SybDriver  
      at com.sun.messaging.jmq.jmsserver.persist.jdbc.comm.CommDBManager.initDBDriver(CommDBManager.java:495)  
      at com.sun.messaging.jmq.jmsserver.persist.jdbc.DBManager.<init>(DBManager.java:259)  
      at com.sun.messaging.jmq.jmsserver.persist.jdbc.DBManager.getDBManager(DBManager.java:182)  
      at com.sun.messaging.jmq.jmsserver.persist.jdbc.JDBCStore.<init>(JDBCStore.java:112)  
      at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)  
      at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)  
      at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)  
      at java.lang.reflect.Constructor.newInstance(Constructor.java:525)  
      at java.lang.Class.newInstance0(Class.java:372)  
      at java.lang.Class.newInstance(Class.java:325)  
      at com.sun.messaging.jmq.jmsserver.persist.StoreManager.getStore(StoreManager.java:169)  
      at com.sun.messaging.jmq.jmsserver.Globals.getStore(Globals.java:995)  
      at com.sun.messaging.jmq.jmsserver.Broker._start(Broker.java:955)  
      at com.sun.messaging.jmq.jmsserver.Broker.start(Broker.java:456)  
      at com.sun.messaging.jmq.jmsserver.Broker.main(Broker.java:2151)  
 Caused by: java.lang.ClassNotFoundException: com.sybase.jdbc3.jdbc.SybDriver  
      at java.net.URLClassLoader$1.run(URLClassLoader.java:366)  
      at java.net.URLClassLoader$1.run(URLClassLoader.java:355)  
      at java.security.AccessController.doPrivileged(Native Method)  
      at java.net.URLClassLoader.findClass(URLClassLoader.java:354)  
      at java.lang.ClassLoader.loadClass(ClassLoader.java:423)  
      at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)  
      at java.lang.ClassLoader.loadClass(ClassLoader.java:356)  
      at java.lang.Class.forName0(Native Method)  
      at java.lang.Class.forName(Class.java:186)  
      at com.sun.messaging.jmq.jmsserver.persist.jdbc.comm.CommDBManager.initDBDriver(CommDBManager.java:467)  
      ... 14 more|#]  

3) Jelikož JMS broker nepodporuje Sybase ASE je třeba pro Sybase ASE vytvořit databázové schema. Na konec souboru ~/glassfish3122/glassfish/domains/domain1/imq/instances/imqbroker/props/config.properties je třeba přidat následující položky:
 # Beginning of properties to plug in a Sybase ASE database  
 #  
 # User name used to open database connection. Replace username.  
 #imq.persist.jdbc.sybase.user=<username>  
 # Optional property to specify whether the database requires a password.  
 #imq.persist.jdbc.sybase.needpassword=[true|false]  
 # Vendor specific JDBC driver.  
 imq.persist.jdbc.sybase.driver=com.sybase.jdbc3.jdbc.SybConnectionPoolDataSource  
 # Vendor specific properties.  
 # Vendor specific database url to get a database connection.  
 # Replace hostname, port and sid in imq.persist.jdbc.oracle.property.url.  
 # imq.persist.jdbc.oracle.property.url=jdbc:oracle:thin:@<hostname>:<port>:<sid>  
 imq.persist.jdbc.sybase.property.implicitCachingEnabled=true  
 imq.persist.jdbc.sybase.property.maxStatements=25  
 # Properties to define the tables used by the broker. Do not modify the schema.  
 # Version table  
 imq.persist.jdbc.sybase.table.MQVER41=\  
      CREATE TABLE ${name} (\  
        STORE_VERSION INTEGER NOT NULL,\  
        LOCK_ID VARCHAR(100),\  
        PRIMARY KEY(STORE_VERSION))  
 # Configuration change record table  
 imq.persist.jdbc.sybase.table.MQCREC41=\  
      CREATE TABLE ${name} (\  
        RECORD IMAGE NOT NULL,\  
        CREATED_TS NUMERIC NOT NULL,\  
        PRIMARY KEY(CREATED_TS))  
 # Broker table  
 imq.persist.jdbc.sybase.table.MQBKR41=\  
      CREATE TABLE ${name} (\  
        ID VARCHAR(100) NOT NULL,\  
        URL VARCHAR(100) NOT NULL,\  
        VERSION INTEGER NOT NULL,\  
        STATE INTEGER NOT NULL,\  
        TAKEOVER_BROKER VARCHAR(100),\  
        HEARTBEAT_TS NUMERIC,\  
        PRIMARY KEY(ID))  
 # Store session table  
 imq.persist.jdbc.sybase.table.MQSES41=\  
      CREATE TABLE ${name} (\  
        ID BIGINT NOT NULL,\  
        BROKER_ID VARCHAR(100) NOT NULL,\  
        IS_CURRENT INTEGER NOT NULL,\  
        CREATED_BY VARCHAR(100) NOT NULL,\  
        CREATED_TS BIGINT NOT NULL,\  
        PRIMARY KEY(ID))  
 imq.persist.jdbc.sybase.table.MQSES41.index.IDX1=\  
      CREATE INDEX ${index} ON ${name} (\  
        BROKER_ID)  
 imq.persist.jdbc.sybase.table.MQSES41.index.IDX2=\  
      CREATE INDEX ${index} ON ${name} (\  
        BROKER_ID, IS_CURRENT)  
 # Destination table  
 imq.persist.jdbc.sybase.table.MQDST41=\  
      CREATE TABLE ${name} (\  
        ID VARCHAR(100) NOT NULL,\  
        DESTINATION IMAGE NOT NULL,\  
        IS_LOCAL INTEGER NOT NULL,\  
        CONNECTION_ID NUMERIC NULL,\  
        CONNECTED_TS NUMERIC,\  
        STORE_SESSION_ID NUMERIC,\  
        CREATED_TS NUMERIC NOT NULL,\  
        PRIMARY KEY(ID))  
 imq.persist.jdbc.sybase.table.MQDST41.index.IDX1=\  
      CREATE INDEX ${index} ON ${name} (\  
        STORE_SESSION_ID)  
 # Interest (consumer) table  
 imq.persist.jdbc.sybase.table.MQCON41=\  
      CREATE TABLE ${name} (\  
        ID NUMERIC NOT NULL,\  
        CLIENT_ID VARCHAR(1024),\  
        DURABLE_NAME VARCHAR(1024),\  
        CONSUMER IMAGE NOT NULL,\  
        CREATED_TS NUMERIC NOT NULL,\  
        PRIMARY KEY(ID))  
 # Interest list (consumer state) table  
 imq.persist.jdbc.sybase.table.MQCONSTATE41=\  
      CREATE TABLE ${name} (\  
        MESSAGE_ID VARCHAR(100) NOT NULL,\  
        CONSUMER_ID NUMERIC NOT NULL,\  
        STATE INTEGER,\  
        TRANSACTION_ID NUMERIC,\  
        CREATED_TS NUMERIC NOT NULL,\  
        PRIMARY KEY(MESSAGE_ID, CONSUMER_ID))  
 imq.persist.jdbc.sybase.table.MQCONSTATE41.index.IDX1=\  
      CREATE INDEX ${index} ON ${name} (\  
        TRANSACTION_ID)  
 imq.persist.jdbc.sybase.table.MQCONSTATE41.index.IDX2=\  
      CREATE INDEX ${index} ON ${name} (\  
        MESSAGE_ID)  
 # Message table  
 imq.persist.jdbc.sybase.table.MQMSG41=\  
      CREATE TABLE ${name} (\  
        ID VARCHAR(100) NOT NULL,\  
        MESSAGE IMAGE NOT NULL,\  
        MESSAGE_SIZE NUMERIC,\  
        STORE_SESSION_ID NUMERIC NOT NULL,\  
        DESTINATION_ID VARCHAR(100),\  
        TRANSACTION_ID NUMERIC,\  
        CREATED_TS NUMERIC NOT NULL,\  
        PRIMARY KEY(ID))  
 imq.persist.jdbc.sybase.table.MQMSG41.index.IDX1=\  
      CREATE INDEX ${index} ON ${name} (\  
        STORE_SESSION_ID, DESTINATION_ID)  
 # Property table  
 imq.persist.jdbc.sybase.table.MQPROP41=\  
      CREATE TABLE ${name} (\  
        PROPNAME VARCHAR(100) NOT NULL,\  
        PROPVALUE IMAGE,\  
        PRIMARY KEY(PROPNAME))  
 # Transaction table  
 imq.persist.jdbc.sybase.table.MQTXN41=\  
      CREATE TABLE ${name} (\  
        ID NUMERIC NOT NULL,\  
        TYPE INTEGER NOT NULL,\  
        STATE INTEGER,\  
        AUTO_ROLLBACK INTEGER NOT NULL,\  
        XID VARCHAR(256),\  
        TXN_STATE IMAGE NOT NULL,\  
        TXN_HOME_BROKER IMAGE,\  
        TXN_BROKERS IMAGE,\  
        STORE_SESSION_ID NUMERIC NOT NULL,\  
        EXPIRED_TS NUMERIC NOT NULL,\  
        ACCESSED_TS NUMERIC NOT NULL,\  
        PRIMARY KEY(ID))  
 imq.persist.jdbc.sybase.table.MQTXN41.index.IDX1=\  
      CREATE INDEX ${index} ON ${name} (\  
        STORE_SESSION_ID)  
 # JMS Bridge TM LogRecord table  
 imq.persist.jdbc.sybase.table.MQTMLRJMSBG41=\  
      CREATE TABLE ${name} (\  
        XID VARCHAR(256) NOT NULL,\  
        LOG_RECORD IMAGE NOT NULL,\  
        NAME VARCHAR(100) NOT NULL,\  
        BROKER_ID VARCHAR(100) NOT NULL,\  
        CREATED_TS NUMERIC NOT NULL,\  
        UPDATED_TS NUMERIC NOT NULL,\  
        PRIMARY KEY(XID))  
 imq.persist.jdbc.sybase.table.MQTMLRJMSBG41.index.IDX1=\  
      CREATE INDEX ${index} ON ${name} (BROKER_ID)  
 imq.persist.jdbc.sybase.table.MQTMLRJMSBG41.index.IDX2=\  
      CREATE INDEX ${index} ON ${name} (NAME)  
 # JMS Bridges table  
 imq.persist.jdbc.sybase.table.MQJMSBG41=\  
      CREATE TABLE ${name} (\  
        NAME VARCHAR(100) NOT NULL,\  
        BROKER_ID VARCHAR(100) NOT NULL,\  
        CREATED_TS NUMERIC NOT NULL,\  
        UPDATED_TS NUMERIC NOT NULL,\  
        PRIMARY KEY(NAME))  
 # End of properties to plug in an Sybase ASE database  
Některé z víše uvedených položek je samozřejmě možné upravit podle vlastních potřeb nebo přidat další.
Kdybychom toto neudělali skončili bychom s touto chybou v logu:
 Local broker: ERROR [B3000]: Could not open persistent message store:  
 com.sun.messaging.jmq.jmsserver.util.BrokerException: Table definition not found for sybase  
      at com.sun.messaging.jmq.jmsserver.persist.jdbc.comm.CommDBManager.loadTableSchema(CommDBManager.java:1215)  
      at com.sun.messaging.jmq.jmsserver.persist.jdbc.DBManager.getDBManager(DBManager.java:183)  
      at com.sun.messaging.jmq.jmsserver.persist.jdbc.JDBCStore.<init>(JDBCStore.java:112)  
      at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)  
      at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)  
      at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)  
      at java.lang.reflect.Constructor.newInstance(Constructor.java:525)  
      at java.lang.Class.newInstance0(Class.java:372)  
      at java.lang.Class.newInstance(Class.java:325)  
      at com.sun.messaging.jmq.jmsserver.persist.StoreManager.getStore(StoreManager.java:169)  
      at com.sun.messaging.jmq.jmsserver.Globals.getStore(Globals.java:995)  
      at com.sun.messaging.jmq.jmsserver.Broker._start(Broker.java:955)  
      at com.sun.messaging.jmq.jmsserver.Broker.start(Broker.java:456)  
      at com.sun.messaging.jmq.jmsserver.Broker.main(Broker.java:2151)|#]  
Více o konfiguraci JMS brokeru je uvedeno zde.
Nyní stačí zapnout Glassfish a zkontrolovat zda se v databázi vytvořili tabulky uvedené ve schematu. Poté je už možné využívat JMS.
V případě zájmu si můžete přečíst více o konfiguraci persistentního uložiště pro Oracle Glassfish Message Queue.
Nastaly problémy, které zde nejsou uvedeny? Podělte se o ně v diskuzi níže.

čtvrtek 31. května 2012

RESTful webová služba 1. díl

  1. Nainstaluji si server glassfish. Ten je možné zdarma získat např. zde. Stačit vám bude ale i Tomcat nebo jiný servletový kontejner.
  2. Vytvořím si v Netbeans novou webovou aplikaci:
  3. V tomto okně je třeba dát Add a následně vybrat nainstalovaný servletový kontejner.
  4. Nyní je třeba nakonfigurovat aplikaci. To je možné dvěma způsoby:

    1.  Prostřednictvím souboru web.xml
    2.  <?xml version="1.0" encoding="UTF-8"?>  
       <web-app xmlns="http://java.sun.com/xml/ns/javaee"  
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
            xsi:schemaLocation="http://java.sun.com/xml/ns/javaee  
       http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">  
         <servlet>  
           <servlet-name>JerseyServlet</servlet-name>  
           <servlet-class>  
             com.sun.jersey.spi.container.servlet.ServletContainer  
           </servlet-class>  
           <load-on-startup>1</load-on-startup>  
         </servlet>  
         <servlet-mapping>  
           <servlet-name>JerseyServlet</servlet-name>  
           <url-pattern>/resources/*</url-pattern>  
         </servlet-mapping>  
       </web-app>  
      

    3. Pomocí anotace @ApplicationPath
    4. 1:  package biz.prodejna.examples.rest;  
      2:    
      3:  import javax.ws.rs.ApplicationPath;  
      4:  import javax.ws.rs.core.Application;  
      5:    
      6:  @ApplicationPath("resources")  
      7:  public class JaxRsConfig extends Application {  
      8:  }  
      

  5. A nyní konečně mohu napsat nějakou svoji třídu.
  6. RESTful webovou službu mohu volat jako bezparametrickou nebo s parametry. V druhém případě mám v podstatě 3 možnosti, jak parametry vkládat:
    • Jako součást URL. Příklad: http://localhost:8080/example-rest/resources/names/jmeno/prijmeni
    • Jako parametry metody GET. Příklad: http://localhost:8080/example-rest/resources/names?jmeno=Adam&prijmeni=Oliva
    • V těle HTTP requestu. Zde mohou být parametry naformátovány v libovolném MIME typu.

    V tomto bodě ukáži pouze první případ. Další případy si nechám do některého z dalších dílů.

    1:  package biz.prodejna.examples.rest;  
    2:    
    3:  import javax.ws.rs.GET;  
    4:  import javax.ws.rs.Path;  
    5:  import javax.ws.rs.PathParam;  
    6:  import javax.ws.rs.Produces;  
    7:    
    8:  @Path("names")  
    9:  public class Names {  
    10:    
    11:    @GET  
    12:    @Path("{first}/{last}")  
    13:    @Produces("text/plain")  
    14:    public String getFullName(  
    15:        @PathParam("first") String firstName, @PathParam("last") String lastName) {  
    16:      return firstName + " " + lastName;  
    17:    }  
    18:  }  
    

    Vysvětlím jednotlivé anotace:
    @Path u třídy udává, pod jakou URL bude služba dostupná.
    @GET definuje, jaká bude použita HTTP metoda.
    @Path u metody definuje, jaké bude pořadí parametrů. Nebo přesněji: jaký tvar bude mít zbytek URL.
    @Produces udává MIME typ v těle HTTP odpovědi.
    @PathParam mapuje parametry metody na části v anotaci @Path

  7. Nyní je už možné aplikaci deployovat na server a zkusit ji zavolat např. z webového prohlížeče: http://localhost:8080/example-rest/resources/names/Adam/Oliva

  8. Proč URL vypadá právě takhle? Vysvětlím:
    example-rest -název aplikace
    resources -definováno ve web.xml nebo anotací @ApplicationPath
    names -definováno anotací třídy @Path
Pokud máte zájem o pokračování tohoto blogu, informujte mě o tom. Co lze očekávat příště:
  • služba vracející odpověď jako xml
  • služba očekávající parametry jako parametry URL
  • tvorba klienta s využitím implementace Jersey.
  • služba očekávající na vstupu XML dokument.

pátek 30. března 2012

GlassFish V3 admin console se načítá příliš dlouho

Pokud máte nainstalovaný GlassFish V3 za proxy a chcete se přihlásit do administrátorské konzole, nejspíš musíte čekat na úvodní obrazovku dosti dlouhou dobu. V logu je pak výpis podobný tomuto:
 admin console: initSessionAttributes()  
 Cannot refresh Catalog : Connection timed out  
Tohoto neduhu se lze zbavit následujícím postupem:

1) Do souboru %GLASSFISH_HOME/glassfish/domains/domain1/domain.xml přidejte následující jvm-option:
 <jvm-options>-Dcom.sun.enterprise.tools.admingui.NO_NETWORK=true</jvm-options> 

2) Odstraňte (raději si ho někam zálohujte) update tool jar z umístění %GLASSFISH_HOME/glassfish/modules/console-updatecenter-plugin.jar

3) Pokud máte čistou instalaci, můžete si dovolit odstranit složky %GLASSFISH_HOME/glassfish/domains/domain1/osgi-cache a %GLASSFISH_HOME/glassfish/domains/domain1/generated. Postup mi fungoval i bez tohoto bodu.

4) %GLASSFISH_HOME/bin/asadmin [re]start-domain

čtvrtek 12. ledna 2012

SSL na více virtuálních serverech v rámci jednoho serveru glassfish

Poblém, který následující řádky řeší je přístup přes https na více domén (druhého řádu) v rámci jednoho glassfishe, kdy domény jsou definovány v rámci virtuálního serveru. Používat více serverových certifikátů na jednom glassfishi v rámci jedné domény možné není. Více o problému zde.

Uvedený problém je řešitelný vydáním certifikátu odpovídající standardu RFC-2818 (http://www.ietf.org/rfc/rfc2818.txt) následujícím způsobem:
V CN bude název jednoho z požadovaných názvů virtuálního serveru. Ostatní názvy virtuálních serverů budou v položce "Alternativní jména subjektu certifikátu" (SubjectAltName), kde je možné umístit jednu nebo více položek dNSName případně iPAddress nebo uniformResourceIdentifier. Tomuto podobných řešení existuje více (např. využití regulárního výrazu v CN), uvedené má ovšem nejlepší interoperabilitu (http://wiki.cacert.org/VhostTaskForce#Interoperability_Test).
Podle zmíněného standardu je možné v dNSName využívat i hvězdičkovou konvenci. Navíc definuje, že CN je použito jako identita až v případě, že není definováno rozšíření subjectAltName typu dNSName. Používání CN je zastaralé a RFC-2818 namísto toho certifikačním autoritám doporučuje používat dNSName.

pátek 1. července 2011

SSL certifikát pro více subdomén spravovaných jedním serverem glassfish

Případ, kdy je více domén 3.řádu (k jedné doméně 2. řádu) obsluhováno jedním serverem je celkem častý. Pokud tyto domény využívají SSL je zde možnost využít  certifikát vystavený pro všechny domény třetího řádu (*.mojedomena.com)
Popíši teď postup pro případ, kdy si vytvořím certifikát podepsaný sám sebou. Budu předpokládat, že alias certifikátu nastavený v http listeneru serveru glassfish se jmenuje s1as. V Admin consoli je toto nastavení v Configuration - Network Config - Network Listeners - http-listener-nazev - záložka SSL - Certificate NickName. Všechni níže uváděné příkazy jsou prováděny v
1) Nejprve smažu dosud používaný privátní klíč:
 keytool -delete -alias s1as -keystore keystore.jks -storepass changeit  
2) Smažu certifikát:
 keytool -delete -alias s1as -keystore cacerts.jks -storepass changeit  
3) Vytvořím privátní klíč:
 keytool -genkey -alias s1as -keypass changeit -storepass changeit -keystore keystore.jks  
4) Předchozí příkaz je interaktivní. Je nutné na otázku "What is your first and last name?" napsat "*.mojedomena.com" další odpovědi již nejsou tolik významené.
5) Exportuji do souboru certifikát:
 keytool -export -alias s1as -storepass changeit -file cert.cer -keystore keystore.jks  
6) Importuji certifikát do cacerts:
 keytool -import -v -trustcacerts -alias s1as -file servercpost.cer -keystore cacerts.jks -keypass changeit -storepass changeit  

Hotovo, nyní by již měl glassfish po restartu na příchozí https požadavky využít nový "hvězdičkový" certifikát.

středa 6. dubna 2011

JAX-WS enterprise application client důvěřující všem serverovým certifikátům

Nedávno jsem vytvořil webovou službu využívající SSL a k ní enterprise aplikačního klienta pro server glassfish za použití JAX-WS. Bylo třeba aby tato dvojice byla spustitelná i na jiném počítači. Tedy klient musel akceptovat i jiné, v době vývoje neznámé, serverové certifikáty. Jedním z možných řešení je vytvořit klienta tak, aby automaticky důvěřoval všem serverovým certifikátům ať obsahují cokoli. Upozorňuji že toto řešení v žádném případě není vhodné pro produkční prostředí.
Aby klient důvěřoval všem certifikátům je třeba vytvořit následující třídu:
1:  import javax.net.ssl.X509TrustManager;  
2:  public class TrustEverythingTrustManager implements X509TrustManager {  
3:      public java.security.cert.X509Certificate[] getAcceptedIssuers() {  
4:        return null;  
5:      }  
6:      public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) {  }  
7:      public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) {  }  
8:    }  

Navíc WSDL, jehož kopie je i lokálně na straně klienta, obsahuje následující adresu: <soap:address location="https://localhost:8181/services/testPort"/>. Pokud server vrátí certifikát jehož CN bude jiné než localhost, což s největší pravděpodobností bude, nastane následující vyjímka:
 java.lang.reflect.InvocationTargetException  
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)  
     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)  
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)  
     at java.lang.reflect.Method.invoke(Method.java:597)  
     at org.glassfish.appclient.client.acc.AppClientContainer.launch(AppClientContainer.java:424)  
     at org.glassfish.appclient.client.AppClientFacade.main(AppClientFacade.java:134)  
 Caused by: com.sun.xml.ws.client.ClientTransportException: HTTP transport error: java.io.IOException: HTTPS hostname wrong: should be <localhost>  
     at com.sun.xml.ws.transport.http.client.HttpClientTransport.getOutput(HttpClientTransport.java:135)  
     at com.sun.xml.ws.transport.http.client.HttpTransportPipe.process(HttpTransportPipe.java:163)  
     at com.sun.xml.ws.transport.http.client.HttpTransportPipe.processRequest(HttpTransportPipe.java:95)  
     at com.sun.xml.ws.transport.DeferredTransportPipe.processRequest(DeferredTransportPipe.java:105)  
     at com.sun.xml.ws.api.pipe.Fiber.__doRun(Fiber.java:629)  
     at com.sun.xml.ws.api.pipe.Fiber._doRun(Fiber.java:588)  
     at com.sun.xml.ws.api.pipe.Fiber.doRun(Fiber.java:573)  
     at com.sun.xml.ws.api.pipe.Fiber.runSync(Fiber.java:470)  
     at com.sun.xml.ws.api.pipe.helper.AbstractTubeImpl.process(AbstractTubeImpl.java:112)  
     at com.sun.enterprise.security.webservices.ClientSecurityPipe.processSecureRequest(ClientSecurityPipe.java:192)  
     at com.sun.enterprise.security.webservices.ClientSecurityPipe.process(ClientSecurityPipe.java:180)  
     at com.sun.xml.ws.api.pipe.helper.PipeAdapter.processRequest(PipeAdapter.java:115)  
     at com.sun.xml.ws.api.pipe.Fiber.__doRun(Fiber.java:629)  
     at com.sun.xml.ws.api.pipe.Fiber._doRun(Fiber.java:588)  
     at com.sun.xml.ws.api.pipe.Fiber.doRun(Fiber.java:573)  
     at com.sun.xml.ws.api.pipe.Fiber.runSync(Fiber.java:470)  
     at com.sun.xml.ws.client.Stub.process(Stub.java:319)  
     at com.sun.xml.ws.client.sei.SEIStub.doProcess(SEIStub.java:157)  
     at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:109)  
     at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:89)  
     at com.sun.xml.ws.client.sei.SEIStub.invoke(SEIStub.java:140)  
     at $Proxy46.testOperation(Unknown Source)  
     at testwsappclient.Main.main(Main.java:62)  
     ... 6 more  
 Caused by: java.io.IOException: HTTPS hostname wrong: should be <localhost>  
     at sun.net.www.protocol.https.HttpsClient.checkURLSpoofing(HttpsClient.java:524)  
     at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:448)  
     at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:166)  
     at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:1014)  
     at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:230)  
     at com.sun.xml.ws.transport.http.client.HttpClientTransport.getOutput(HttpClientTransport.java:123)  
     ... 28 more  

Pro tento případ potřebujeme vytvořit další třídu:
1:  import javax.net.ssl.HostnameVerifier;  
2:  import javax.net.ssl.SSLSession;  
3:  public class VerifyEverythingHostnameVerifier implements HostnameVerifier {  
4:    public boolean verify(String string, SSLSession sslSession) {  
5:      return true;  
6:    }  
7:  }  

A nyní obě třídy využijeme v kódu klienta:
1:  public class Main {  
2:    @WebServiceRef(wsdlLocation = "META-INF/test.wsdl")  
3:    private static TestService service;  
4:    public static void main(String[] args) {  
5:      Main main = new Main();  
6:      TestPortType port = service.getTestPort();  
7:      ((BindingProvider) port).getRequestContext().put(BindingProvider.USERNAME_PROPERTY, "user");  
8:      ((BindingProvider) port).getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, "password");  
9:      HostnameVerifier hostNameVerifier = new VerifyEverythingHostnameVerifier();  
10:      ((BindingProvider) port).getRequestContext().put("com.sun.xml.ws.transport.https.client.hostname.verifier", hostNameVerifier);  
11:      SSLContext sslContext;  
12:      try {  
13:        TrustManager[] trustManager = new TrustManager[]{new TrustEverythingTrustManager()};  
14:        sslContext = SSLContext.getInstance("SSL");  
15:        sslContext.init(null, trustManager, new java.security.SecureRandom());  
16:        HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());  
17:      } catch (NoSuchAlgorithmException ex) {  
18:        Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);  
19:      } catch (KeyManagementException ex) {  
20:        Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);  
21:      }  
22:      ObjectFactory of = new ObjectFactory();  
23:      TestOperationRequest req = of.createTestOperationRequest();  
24:      req.setFirstName("Fist");  
25:      req.setLastName("Last");  
26:      try {  
27:        String back = port.testOperation(req);  
28:        System.out.println(back);  
29:      } catch (TestOperationFault ex) {  
30:        Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);  
31:      }  
32:    }  
33:  }  

Obdobný problém u REST služby je řešen zde.

úterý 15. února 2011

Import privátních klíčů PKCS12 do JKS keystoru glassfishe

Výchozí stav: mám soubor od certifikační autority s příponou p12, heslo k privátnímu klíči a potřebuji ho použít pro SSL v glassfishi jako náhradu za prošlý certifikát
Krok 1: nejprve je třeba z keystore.jks odstranit onen prošlý certifikát:
 keytool -delete -alias alias -keystore keystore.jks -storepass changeit -v  

Krok 2: import obsahu p12 do keystore.jks
 keytool -v -importkeystore -srckeystore cert_auth.p12 -srcstoretype PKCS12 -destkeystore keystore.jks -deststoretype JKS  

Krok 3: Dost možná nemá importovaný klíč stejný alias jaký bychom si představovali. My bychom např. chtěli aby se jmenoval ap1as1 a on se jmenuje authkey#1, to lze vyřešit následovně:
 keytool -changealias -alias authkey#1 -destalias ap1as1 -keystore keystore.jks  

Po zadání tohoto příkazu se keytool nejprve zeptá na heslo pro keystore a poté na heslo ke klíči, který jsme v předchozím kroku importovali.
Krok 4: V tomto stavu by po restartu glassfishe pravděpodobně nastala chyba java.security.UnrecoverableKeyException: Cannot recover key Důvodem je jiné heslo pro nově importovaný klíč a jiné heslo pro keystore. Hesla lze sjednotit následovně:
 keytool -keypasswd -alias ap1as1 -keypass oldKeyPassword -new changeit -keystore keystore.jks -storepass changeit -v  

Nyní by mělo stačit restartovat glassfish.

středa 19. května 2010

Spouštění serveru glassfish při startu ubuntu.

V oblíbeném editoru (zde gedit) vytvořit soubor jménem /etc/init.d/glassfish
 sudo gedit /etc/init.d/glassfish  

Do souboru vložíme následující text:
 #! /bin/sh  
 GLASSFISHPATH=/opt/glassfishv3/bin  
 case "$1" in  
 start)  
 echo "starting glassfish from $GLASSFISHPATH"  
 sudo -u glassfish $GLASSFISHPATH/asadmin start-domain domain1  
 ;;  
 restart)  
 $0 stop  
 $0 start  
 ;;  
 stop)  
 echo "stopping glassfish from $GLASSFISHPATH"  
 sudo -u glassfish $GLASSFISHPATH/asadmin stop-domain domain1  
 ;;  
 *)  
 echo $"usage: $0 {start|stop|restart}"  
 exit 3  
 ;;  
 esac  
 :  

Uživatele glassfish je třeba v obou případech (-u glassfish) změnit podle vlastních potřeb na existujícího uživatele pod jehož právy se bude glassfish spouštět. Také je třeba upravit druhý řádek podle toho, kde je glassfish nainstalovaný.
Soubor uložit, editor zavřít a nyní je třeba změnit uživatelská práva souboru:
 sudo chmod a+x /etc/init.d/glassfish  

Nyní nainstalovat na všechny úrovně běhu:
 sudo update-rc.d glassfish defaults  

Hotovo. Po restartování počítače by se již měl glassfish spouštět sám.