2009-12-14 11 views
4

J'ai un problème avec GlassFish et connecteur SAP JCo (sapjco3.jar)connecteur SAP JCo chargé pour toujours dans GlassFish v2.1 (ne peut pas décharger)

Je le charge au démarrage d'une application J2EE (jwm.ear) et l'initialiser dans un singleton la première fois qu'une connexion à SAP est nécessaire.

Le problème est que ce pot reste toujours initialisé en mémoire, j'ai besoin de redémarrer glassfish pour décharger les connexions initialisées si j'ai besoin de changer un seul paramètre. L'arrêt ou le non-déploiement de l'application ne décharge pas sapjco.jar et les redéploiements furter de l'application n'obtiennent jamais les nouveaux paramètres de connexion, la première initialisation reste jusqu'à ce que GlassFish redémarre.

Est-ce que quelqu'un sait comment décharger ou réinitialiser cette bibliothèque? De préférence même sans redéployer l'application, la première fois que l'application est activée J'ai une référence à jcoProvider, les prochaines activations obtiennent une référence null à jcoProvider, mais un jcoProvider continue instancié en mémoire avec des valeurs initiales.

Cordialement!

Notes: GlassFish est la version 2.1 dans Windows Server 2008, est jdk 1.6.0.14 sapjco3.jar et sapjco3.dll sont copiés dans \ domaines \ domain1 \ lib \ ext et sont la version 3 du connecteur SAP java.

Singleton pour obtenir des connexions SAP:

 
package es.grupotec.ejb.SAP; 

import com.sap.conn.jco.JCoDestination; 
import com.sap.conn.jco.JCoDestinationManager; 
import com.sap.conn.jco.JCoException; 
import com.sap.conn.jco.ext.DestinationDataProvider; 
import com.sap.conn.jco.ext.Environment; 
import es.grupotec.ejb.util.ConexionSAPException; 
import java.util.Properties; 

public final class SAP { 

    private static String SAP_SERVER = "JWM"; 
    private static SAP instance = null; 
    private static JCOProvider jcoProvider = null; 

    private SAP() { 
     // Exists only to defeat instantiation. 
    } 

    // Get SAP connection 
    public static synchronized JCoDestination getDestination() throws ConexionSAPException { 

     JCoDestination jcoDestination = null; 

      if (Environment.isDestinationDataProviderRegistered()) { 
       try { 

        jcoDestination = JCoDestinationManager.getDestination(SAP_SERVER); 
        return jcoDestination; 

       } catch (JCoException ex) { 

        throw new ConexionSAPException(ex.getMessage()); 

       } 
      } 

     // Create new connection 
     if(jcoProvider == null) init(); 

     // Get connection 
     try { 

      jcoDestination = JCoDestinationManager.getDestination(SAP_SERVER); 
      return jcoDestination; 

     } catch (JCoException ex) { 

      throw new ConexionSAPException(ex.getMessage()); 

     } 

    } 

    // Initialize connection to SAP 
    public static synchronized void init() throws ConexionSAPException { 

     SAPVO sap = new SAPVO(); 
     Properties properties = new Properties(); 

     if(jcoProvider == null) { 


      // Get SAP config from database 
      try { 
       sap = SAPDAO.getSAPConfig(); 
      } catch (Exception ex) { 
       throw new ConexionSAPException(ex.getMessage()); 
      } 

      // Create connection object 
      jcoProvider = new JCOProvider(); 

     } 

     properties.setProperty(DestinationDataProvider.JCO_ASHOST,  sap.getJCO_ASHOST()); 
     properties.setProperty(DestinationDataProvider.JCO_SYSNR,   sap.getJCO_SYSNR()); 
     properties.setProperty(DestinationDataProvider.JCO_CLIENT,  sap.getJCO_CLIENT()); 
     properties.setProperty(DestinationDataProvider.JCO_USER,   sap.getJCO_USER()); 
     properties.setProperty(DestinationDataProvider.JCO_PASSWD,  sap.getJCO_PASSWD()); 
     properties.setProperty(DestinationDataProvider.JCO_LANG,   sap.getJCO_LANG()); 

     try { 

      jcoProvider.changePropertiesForABAP_AS(properties); 

     } catch (Exception e) { 

      throw new ConexionSAPException(e.getMessage()); 

     } 

    } 

    public static synchronized void change(SAPVO sap) throws ConexionSAPException { 

     Properties properties = new Properties(); 

     // If connection is null create a new one 
     if(jcoProvider == null) jcoProvider = new JCOProvider(); 

     properties.setProperty(DestinationDataProvider.JCO_ASHOST,  sap.getJCO_ASHOST()); 
     properties.setProperty(DestinationDataProvider.JCO_SYSNR,   sap.getJCO_SYSNR()); 
     properties.setProperty(DestinationDataProvider.JCO_CLIENT,  sap.getJCO_CLIENT()); 
     properties.setProperty(DestinationDataProvider.JCO_USER,   sap.getJCO_USER()); 
     properties.setProperty(DestinationDataProvider.JCO_PASSWD,  sap.getJCO_PASSWD()); 
     properties.setProperty(DestinationDataProvider.JCO_LANG,   sap.getJCO_LANG()); 

     try { 

      jcoProvider.changePropertiesForABAP_AS(properties); 

     } catch (Exception e) { 

      throw new ConexionSAPException(e.getMessage()); 

     } 


    } 

    // Prevent instantiation by clone 
    @Override 
    public Object clone() throws CloneNotSupportedException { 

     throw new CloneNotSupportedException(); 

    } 

} 

mise en œuvre du fournisseur JCo:

 
package es.grupotec.ejb.SAP; 

import com.sap.conn.jco.ext.DestinationDataEventListener; 
import com.sap.conn.jco.ext.DestinationDataProvider; 
import com.sap.conn.jco.ext.Environment; 
import es.grupotec.ejb.util.ConexionSAPException; 
import java.util.Properties; 

public class JCOProvider implements DestinationDataProvider { 

    private String SAP_SERVER = "JWM"; 
    private DestinationDataEventListener eventListener; 
    private Properties ABAP_AS_properties; 

    public JCOProvider(){ 

    } 

    public JCOProvider(SAPVO sap){ 

     ABAP_AS_properties = new Properties(); 
     ABAP_AS_properties.setProperty(DestinationDataProvider.JCO_ASHOST,  sap.getJCO_ASHOST()); 
     ABAP_AS_properties.setProperty(DestinationDataProvider.JCO_SYSNR,   sap.getJCO_SYSNR()); 
     ABAP_AS_properties.setProperty(DestinationDataProvider.JCO_CLIENT,  sap.getJCO_CLIENT()); 
     ABAP_AS_properties.setProperty(DestinationDataProvider.JCO_USER,   sap.getJCO_USER()); 
     ABAP_AS_properties.setProperty(DestinationDataProvider.JCO_PASSWD,  sap.getJCO_PASSWD()); 
     ABAP_AS_properties.setProperty(DestinationDataProvider.JCO_LANG,   sap.getJCO_LANG()); 
     ABAP_AS_properties.setProperty(DestinationDataProvider.JCO_POOL_CAPACITY, sap.getJCO_POOL_CAPACITY()); 
     ABAP_AS_properties.setProperty(DestinationDataProvider.JCO_PEAK_LIMIT, sap.getJCO_PEAK_LIMIT()); 

     try { 
      if (!Environment.isDestinationDataProviderRegistered()) 
       Environment.registerDestinationDataProvider(this); 
      else changePropertiesForABAP_AS(ABAP_AS_properties); 
     } catch (Exception ex) { 
      String msg = ex.getMessage(); 
     } 

    } 

    @Override 
    public Properties getDestinationProperties(String name) { 

     if (name.equals(SAP_SERVER) && ABAP_AS_properties!=null) return ABAP_AS_properties; 
     else return null; 

    } 

    @Override 
    public boolean supportsEvents() { 
     return true; 
    } 

    @Override 
    public void setDestinationDataEventListener(DestinationDataEventListener eventListener) { 
     this.eventListener = eventListener; 
    } 

public void changePropertiesForABAP_AS(Properties properties) throws ConexionSAPException { 

     try { 

      if (!Environment.isDestinationDataProviderRegistered()) { 

       if (ABAP_AS_properties == null) ABAP_AS_properties = properties; 
       Environment.registerDestinationDataProvider(this); 

      } 

      if (properties == null) { 

       if (eventListener != null) eventListener.deleted(SAP_SERVER); 
       ABAP_AS_properties = null; 

      } else { 

       ABAP_AS_properties = properties; 
       if (eventListener != null) eventListener.updated(SAP_SERVER); 

      } 

     } catch (Exception ex) { 

      throw new ConexionSAPException(ex.getMessage()); 

     } 

} 

} 

Répondre

3

Votre problème est probablement lié au fait qu'il existe un code natif impliqué ici. C'est même vrai pour JCo 3. Alors que JCo 3 n'utilise plus la bibliothèque RFC native, elle a toujours besoin de JNI pour communiquer avec la couche CPIC. Obtenir une JVM pour décharger une bibliothèque native est un exercice extrêmement frustrant. La spécification JNI indique qu'une bibliothèque native sera déchargée lorsque le ClassLoader associé à la classe à laquelle elle fournit l'implémentation est déchargé, mais que tenter de forcer un ClassLoader à se décharger est pratiquement impossible au sein de la JVM.

Si votre fichier EAR inclut le fichier sapjco3.jar, il sera rechargé chaque fois que votre code est rechargé. Cela entraînera probablement des exceptions car la bibliothèque native ne peut pas être chargée plus d'une fois et il n'y a pratiquement aucun moyen de décharger le code natif. Vous pouvez donc envisager de placer le fichier sapjco3.jar à l'extérieur du conteneur J2EE et laisser votre moteur J2EE charger cette bibliothèque une seule fois au démarrage, plutôt que de le placer dans le fichier EAR qui sera rechargé à plusieurs reprises.

+0

Oui, je me suis d'abord battu avec ce problème (inclus dans .ear), maintenant sapjco3.jar et sapjco3.dll sont placés dans domaines/domain1/lib/ext et fonctionne très bien, le seul problème est en cas de changements de connexion SAP, donc ils ne sont pas communs, il est seulement nécessaire de redémarrer glassfish lorsque SAP force un changement de mot de passe se connectent avec. Je pensais en classloader mais c'est de la magie noire pour moi. Merci beaucoup. – franblay

+0

Même après avoir placé sapjco3.jar sous le chemin lib/ext, vous devriez toujours pouvoir créer, supprimer, modifier vos objets de destination et de fournisseur JCo dans le cadre de votre conteneur. Par conséquent, je ne vois pas pourquoi on ne devrait pas être capable de modifier un objet de connexion JCo en modifiant l'une des propriétés de la connexion comme son mot de passe. – Tom

+0

Oui, oui, nous pouvons faire un changePropertiesForABAP_AS chaque fois qu'un changement dans la connexion se produit ... mais dans la mesure où vous avez un "nouveau" déploiement de l'application. Si nous faisons un redéploiement, ou une désactivation/activation, le lien entre notre application. et l'objet de connexion jco est brisé. Nous pouvons utiliser la connexion, car elle est en quelque sorte vivante mais nous ne pouvons pas la changer. jcoDestination = JCoDestinationManager.getDestination(); fonctionne toujours, mais après une mise à jour de l'application changePropertiesForABAP_AS échoue, objet eventListener = NULL. Nous devons redémarrer le serveur. Peut-être que j'ai raté un point dans les connecteurs internes du connecteur jco .... – franblay

0

À quelle version de SAP avez-vous l'intention de vous connecter? Nous avons eu plusieurs problèmes avec Java Connector, ce n'était pas vraiment threadsafe et ne pouvait pas être intégré dans une application EJB correctement. Les mêmes problèmes sont survenus avec SAP Seculib pour l'authentification unique. Cela n'a pas fonctionné. La seule solution était de le charger en dehors du moteur J2EE.

Avez-vous déjà pensé à remplacer le JCO par des services Web? Bien sûr, c'est un peu plus lent car les données doivent passer par l'ICF mais c'est plus robuste. Nous avons basculé toutes nos intégrations vers cette solution.

+0

Le connecteur de sap fonctionne très bien, le seul problème est ce que j'ai demandé et nous pouvons vivre avec, c'est une solution "moche" mais nous pouvons nous permettre un redémarrer unpon un changement de connexion unique (mot de passe utilisateur la plupart du temps) J'ai pensé à des services Web, mais c'est une application très intensive. avec des sinchronisations et des exécutions BAPI toutes les 5 s. ou alors et parfois de grandes quantités de données. WS sont plus "asincrones" et nous avions besoin de ce sentiment de "tout sous contrôle" avec RFC. Mais c'est une façon d'avoir en tête. Merci beaucoup. – franblay