Visualizzazione dei risultati da 1 a 7 su 7
  1. #1
    Utente di HTML.it L'avatar di GabbOne
    Registrato dal
    Mar 2006
    Messaggi
    577

    jdom.Document e sincronizzazione

    Come premessa vi dico che la classe che sto costruendo è da inserire in un contesto di un'applicazione web based ed in particolare all'interno di alcune servlet (in realtà tutte ). Inoltre questa classe è costruita utilizzando un design pattern singleton e quindi tutti i thread che vengono lanciati (i.e. servlet) utilizzarano tutte una singola istanza di questa mia classe.

    Arriviamo al problema
    Ho dichiarato in questa classe due oggetti jdom.Document che come ben saprete servono per mantenere in memoria un file xml e ho pensato di dichiararli come attributi di classe in modo tale che tutti i metodi che li utilizzano non fossero costretti a rileggere l'intero file prima di poter operare . Per realizzare cio ho messo nel costruttore (che per come è struttaro il singleton si trova già in un blocco sincronizzato) operazioni di questo tipo :
    codice:
    documentObjectXML = saxBuilder.build(new File(objPathXML));
    .
    che caricano effettivamente in Document il contenuto xml.

    Adesso nella mia classe tutti i metodi utilizzano questi due oggetti document o per fare un lettura di dati o per scriverci su e a me pare tanto che questa sia una situazione in cui cè tanto bisogno di sincronizzare le letture e le scritture

    La mia prima idea è stata quella di dichiarare synchronized tutti i metodi della mia classe ma il piccolo problema è che visto che ho 6 metodi che leggono ( che tra le altre cose sono sicuramente le operazioni che vengono piu utilizzate) e solo 2 che scrivono (con una bassa percentuale di utilizzo) allora mi troverei in una situazione che anche in presenza di 100 letture , che potrebbero avvenire in parallelo , queste risulterebberto tutte loccate tra loro.

    Poi guardando la documentazione (javadoc) di jdom nn sono riuscito a capire se queste siano classi che in qualche modo sono già sincronizzate , in realtà nenche so come si fa ( qualcuno me lo spiega ) , perche in tal caso nn ci sarebbe neanche bisogno di sincronizzare i miei metodi.

    http://www.jdom.org/docs/apidocs/org/jdom/Document.html

    Avete qualche consiglio per uscire da questa situazione ?


    Bella pe tutti

  2. #2
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Innanzitutto bisognerebbe vedere meglio cosa devi fare di preciso e cosa hai già scritto a livello di codice. Già la tua affermazione "ho pensato di dichiararli come attributi di classe in modo tale che tutti i metodi che li utilizzano non fossero costretti a rileggere l'intero file prima di poter operare" mi lascia un po' perplesso.

    E riguardo al tuo dubbio sulla thread safety di JDOM, la FAQ ufficiale ha la risposta: Is JDOM thread safe?

    Per il resto, come ho detto, bisognerebbe vedere meglio il contesto e le necessità ... di più .. così su due piedi non potrei dire altro.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  3. #3
    Utente di HTML.it L'avatar di GabbOne
    Registrato dal
    Mar 2006
    Messaggi
    577
    Originariamente inviato da andbin
    E riguardo al tuo dubbio sulla thread safety di JDOM, la FAQ ufficiale ha la risposta: Is JDOM thread safe? .
    Se ho capito bene in questa FAQ si dice che la libreria jdom non contiene blocchi di codice synchronized e se si ha proprio la necessità di sincronizzare bisogna forse farlo su di una istanza di document . giusto?

    Originariamente inviato da andbin
    Innanzitutto bisognerebbe vedere meglio cosa devi fare di preciso e cosa hai già scritto a livello di codice. Già la tua affermazione "ho pensato di dichiararli come attributi di classe in modo tale che tutti i metodi che li utilizzano non fossero costretti a rileggere l'intero file prima di poter operare" mi lascia un po' perplesso.
    Posto un po di codice anche se devo tagliare molto perche sono già arrivato ad una classe di 700 righe di codice ...

    codice:
    public class Rbac implements RBACInterface {
    
        //l’istanza unica da pubblicare
        private static Rbac instance = null;
        private static Object sinc = new Object(); //oggetto usato per il lock dell'instanziazione
    
    
        final private  String rolePathXML = "src/app/sourceXML/RolesXMLDocument.xml";
        final private  String objPathXML = "src/app/sourceXML/objectXMLDocument.xml";
        final private  String operationPathXML = "src/app/sourceXML/operationXMLDocument.xml";
    
        private Document documentRoleXML = null;
        private Document documentObjectXML  = null;
        private Document documentOperationXML = null;
    
        
        //l’interfaccia unica per accedere alla sola istanza
        public static Rbac getInstance() 
        {
          if(instance == null) {
            synchronized(sinc){//sincronizziamo l'accwesso all'istanziazione di Rbac
              if(instance == null) instance = new Rbac();  
            }       
          }
          return instance;  
        }
    
        private Rbac () {
            try
            {
                    /* Portiamo in memoria tutti i file XML */
                    SAXBuilder saxBuilder = new SAXBuilder();
    
                    documentObjectXML = saxBuilder.build(new File(objPathXML));
                    documentOperationXML = saxBuilder.build(new File(operationPathXML));
                    documentRoleXML = saxBuilder.build(new File(rolePathXML));
            }
            catch (JDOMException ex)
            {
                System.err.println(ex);
            }
            catch (IOException ex)
            {
                System.err.println(ex);
            }
        }
    
    
    
        /* ESEMPIO DI LETTURA */
        
        public RBAC.Object getObject (int idObj)
        {
            RBAC.Object obj=null;
            Element root = documentObjectXML.getRootElement();
    
            /*Lettura Oggetti*/
            Iterator objectIt = root.getChildren().iterator();
            while (objectIt.hasNext())/*Scansione   oggetti */
            {
                Element tmpObject = (Element)objectIt.next();
    
                int tmpId =Integer.parseInt(tmpObject.getAttributeValue("id"));
                if(idObj == tmpId) /* oggetto trovato */
                {
                     obj = new RBAC.Object();
                     obj.setId(idObj);
                     obj.setName(tmpObject.getAttributeValue("name"));
                     obj.setDescription(tmpObject.getAttributeValue("description"));
    
                     Element aux = tmpObject.getChild("operations");
                     if (aux!=null) /*SE lo troviamo passiamo alla scnsione dele proprietà*/
                     {
                        Set<String> operations =new HashSet();
                        Iterator operationsIt = aux.getChildren().iterator();
                        while (operationsIt.hasNext())/*Scansione dei  Ruoli*/
                        {
                            Element operationXML = (Element)operationsIt.next();
                            operations.add(operationXML.getAttributeValue("id"));
                        }
                        obj.setOperations(operations);
                     }
                }
            }
            return obj;
        }
    
    
     /* ESEMPIO DI SCRITTURA */
    
       public void addObject(int idObj,String name,String description)throws AddObjectException
        {
            //questo parametro è richiesto
            if(name==null || name.equals(""))throw new AddObjectException("Il nome dell'oggetto non può essere vuoto o nullo");
    
            RBAC.Object obj =getObject(idObj);
            if(obj != null) throw new AddObjectException("Oggetto già esistente (verificare l'id)");
    
            Element root = documentObjectXML.getRootElement();
    
            Element elementObj = new Element("object");
            elementObj.setAttribute("id", String.valueOf(idObj));
            elementObj.setAttribute("name", name);
            elementObj.setAttribute("description", description);
            root.addContent(elementObj);
    
            writeDocumentXml(documentObjectXML,objPathXML);
    
        }
    
    
    
      /*  writeDocumentXml */
      private void writeDocumentXml(Document document , String pathFile)
        {   /* Metodo per la scrittura su file XML */
            XMLOutputter xmlOutputter = new XMLOutputter();
            xmlOutputter.setFormat(Format.getPrettyFormat());
            try
            {
                FileOutputStream fileOutputStream = new FileOutputStream(pathFile);
                xmlOutputter.output(document, fileOutputStream);
            }
            catch (FileNotFoundException ex)
            {
                System.err.println(ex);
            }
            catch (IOException ex)
            {
                System.err.println(ex);
            }
        }

  4. #4
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Originariamente inviato da GabbOne
    Se ho capito bene in questa FAQ si dice che la libreria jdom non contiene blocchi di codice synchronized
    Sì ... hai capito. JDOM non è di per sé thread-safe, non implementa alcun tipo di sincronizzazione.

    Originariamente inviato da GabbOne
    e se si ha proprio la necessità di sincronizzare bisogna forse farlo su di una istanza di document . giusto?
    Non è che devi farlo per forza (e solo) sul Document. Il concetto è che bisogna gestire una sincronizzazione al di fuori di JDOM tale per cui la gestione delle letture/modifiche al documento sia thread-safe.

    E tieni sempre presente che la sincronizzazione non serve solo per la "mutua-esclusione" ma anche per la "visibilità"!! Immagina di usare JDOM ma senza usare alcuna sincronizzazione: un tuo thread A crea un Element X che poi aggiunge come figlio del Element Y e poi va a fare altro. Poco dopo (appena dopo che A ha aggiunto il figlio) entra in scena un altro tuo thread B che vuole iterare sui figli di Y. Chi ti garantisce che "vedrà" (e in quale stato, ammesso che lo veda) il figlio X aggiunto da A??? Appunto .... senza sincronizzazione non c'è alcuna garanzia!!

    Originariamente inviato da GabbOne
    Posto un po di codice anche se devo tagliare molto perche sono già arrivato ad una classe di 700 righe di codice ...
    No ... purtroppo così non va bene.

    Prima dicevi che avevi usato variabili di "classe" per i Document ... ma io qui vedo che sono di istanza. E questo comunque mi sta già meglio di prima.

    Nel getInstance() hai usato l'idioma del "double-check locking" (DCL). Non va bene. Il DCL era stato ideato quando, nelle versioni più "giovani" della JVM, la sincronizzazione (anche in caso di lock non conteso) era molto "costosa".
    Ora non è più così ... con le moderne JVM la sincronizzazione è meno costosa e se il lock non è conteso, va ancora meglio.
    Come l'hai fatto tu il DCL soffre di un problema ... problema di "visibilità" perché la tua variabile 'instance' è acceduta nel primo if da più thread ma senza garanzia di "visibilità" delle modifiche da parte di altri thread.
    Il DCL funziona bene solo a partire da Java 5 e solo a condizione di marcare la variabile che tiene la istanza con il modificatore "volatile". Senza ... possono esserci grane.

    Al giorno d'oggi il DCL è ancora utile per inizializzare in modo "lazy" variabili di istanza ma ... per variabili di classe esiste un altro idioma, più pratico, semplice e anche più interessante (e purtroppo poco conosciuto): il "lazy initialization holder class" (lo trovi spiegato qui ad esempio).

    Passiamo ad altro di più "leggero" (la sincronizzazione è difficile ... lo so) ovvero le eccezioni. Hai catturato e gestito le eccezioni nel tuo codice (nel costruttore di Rbac e in writeDocumentXml()). Non va affatto bene. Le eccezioni dovrebbero "uscire" fuori da lì, non essere catturate a quel livello! Se nel costruttore salta fuori una di quelle eccezioni, certamente stampi su std-err le varie informazioni della eccezione .... ma l'oggetto viene comunque creato e ritornato (e in uno stato potenzialmente "inconsistente" quindi non usabile) e tu dall'esterno non te ne puoi accorgere ... se non più avanti quando ti sbucano fuori altre eccezioni dovute al fatto che hai usato l'oggetto in uno stato inconsistente.

    Rivedi bene il tutto.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  5. #5
    Utente di HTML.it L'avatar di GabbOne
    Registrato dal
    Mar 2006
    Messaggi
    577
    Wow non pensavo che il mio codice facesse così schifo , cmq prendiamola con filosofia... sbagliando si impara


    Allora affrontiamo un problema per volta , parto dal leggero perche attualmente è domenica mattina :\ .

    Passiamo ad altro di più "leggero" (la sincronizzazione è difficile ... lo so) ovvero le eccezioni. Hai catturato e gestito le eccezioni nel tuo codice (nel costruttore di Rbac e in writeDocumentXml()). Non va affatto bene. Le eccezioni dovrebbero "uscire" fuori da lì, non essere catturate a quel livello! Se nel costruttore salta fuori una di quelle eccezioni, certamente stampi su std-err le varie informazioni della eccezione .... ma l'oggetto viene comunque creato e ritornato (e in uno stato potenzialmente "inconsistente" quindi non usabile) e tu dall'esterno non te ne puoi accorgere ... se non più avanti quando ti sbucano fuori altre eccezioni dovute al fatto che hai usato l'oggetto in uno stato inconsistente.
    sinceramente nn so cosa cercare sul web per risolvere questo ma ho pensato che una possibile soluzione sia questa :

    codice:
        private Rbac () throws JDOMException , IOException{
            try
            {
                    /* Portiamo in memoria tutti i file XML */
                    SAXBuilder saxBuilder = new SAXBuilder();
    
                    documentObjectXML = saxBuilder.build(new File(objPathXML));
                    documentOperationXML = saxBuilder.build(new File(operationPathXML));
                    documentRoleXML = saxBuilder.build(new File(rolePathXML));
            }
            catch (JDOMException ex)
            {
                throw new JDOMException();
            }
            catch (IOException ex)
            {
               throw new JDOMException();
            }
        }
    che in partica forza i client a gestire le eccezzioni jdom , questa modifica impatta naturalmente anche su sul metodo getIstance() che dovrebbe diventare così

    codice:
        public static Rbac getInstance()throws JDOMException , IOException 
        {
          try{
                if(instance == null) {
                    synchronized(sinc){//sincronizziamo l'accwesso all'istanziazione di Rbac
                    if(instance == null) instance = new Rbac();  
                    }       
                }
            return instance;
          }
          catch (JDOMException ex)
          {
            throw new JDOMException();
          }
          catch (IOException ex)
          {
            throw new JDOMException();
          }
          catch (Exception ex)
          {
            return null; // <-- ok?
          }
        }
    nn so io ho pensato di fare così poiche sono cmq costretto ad intercettare l'eccezzione di jdom , ma invece di gestirla la rilancio al chiamante .

    ps.
    Scommetto che nn va bene neanche così

  6. #6
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Originariamente inviato da GabbOne
    sinceramente nn so cosa cercare sul web per risolvere questo ma ho pensato che una possibile soluzione sia questa :
    No. La questione è semplice: in quella tua classe, a quel livello, c'è ben poco che tu possa fare per "reagire" alla eccezione .... quindi dovrebbe essere il chiamante (o ancora più in su ... dipende da cosa succede di sopra...) a catturare la eccezione e fare "qualcosa". Se fosse una applicazione Swing allora potrebbe mostrare una box di errore, se fosse una servlet potrebbe fare il forward ad una pagina di errore o altro.

    Insomma, questa tua classe Rbac è ignara ... inconsapevole di dove/come sarà usata, quindi non dovrebbe cercare di reagire in alcun modo specifico alla eccezione. È al "di sopra" che si è ad un livello più consapevole della architettura, in generale, della applicazione e dell'interfacciamento con l'utente.

    In questo tuo codice se vuoi puoi catturare la eccezione, uno scopo valido infatti ci sarebbe ovvero il "logging" della eccezione (per logging si va dal banale System.out.println() all'uso di librerie apposite di logging es. Log4J o altre). Ma a quel punto dovresti comunque sempre rilanciare la eccezione .... che non vuol dire istanziarne una nuova (come hai mostrato sopra)!!!!

    In sostanza hai 2 possibilità:

    codice:
    private Rbac() throws JDOMException, IOException {
        SAXBuilder saxBuilder = new SAXBuilder();
    
        documentObjectXML = saxBuilder.build(new File(objPathXML));
        documentOperationXML = saxBuilder.build(new File(operationPathXML));
        documentRoleXML = saxBuilder.build(new File(rolePathXML));
    }
    In pratica lasci solamente e semplicemente uscire le eccezioni al di fuori.

    Oppure

    codice:
    private Rbac() throws JDOMException, IOException {
        try {
            SAXBuilder saxBuilder = new SAXBuilder();
    
            documentObjectXML = saxBuilder.build(new File(objPathXML));
            documentOperationXML = saxBuilder.build(new File(operationPathXML));
            documentRoleXML = saxBuilder.build(new File(rolePathXML));
        } catch (JDOMException ex) {
            // Qui fai del logging ....
            throw ex;               // RILANCIA!!!!
        } catch (IOException ex) {
            // Qui fai del logging ....
            throw ex;               // RILANCIA!!!!
        }
    }
    Lasci ancora sempre uscire fuori le eccezioni ma prima le catturi, fai del "logging" e poi le rilanci. Nota il throw ex, è così che si rilancia. Non devi istanziare nulla!!! La eccezione è già stata istanziata (dentro JDOM), devi solo rilanciarla.

    E in getInstance() non devi fare nulla di particolare, né catturare né rilanciare nulla. Basta solo dichiarare il throws JDOMException, IOException. Tutto qui.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  7. #7
    Utente di HTML.it L'avatar di GabbOne
    Registrato dal
    Mar 2006
    Messaggi
    577
    ok riproviamoci
    codice:
        private Rbac () throws JDOMException , IOException{
    
                    /* Portiamo in memoria tutti i file XML */
                    SAXBuilder saxBuilder = new SAXBuilder();
    
                    documentObjectXML = saxBuilder.build(new File(objPathXML));
                    documentOperationXML = saxBuilder.build(new File(operationPathXML));
                    documentRoleXML = saxBuilder.build(new File(rolePathXML));
    
        }
    codice:
        public static Rbac getInstance()throws JDOMException , IOException
        {
          try{
                if(instance == null) {
                    synchronized(sinc){//sincronizziamo l'accwesso all'istanziazione di Rbac
                    if(instance == null) instance = new Rbac();
                    }
                }
            return instance;
          }
          catch (JDOMException ex)
          {
              System.err.println(ex);
              throw ex;
          }
          catch (IOException ex)
          {
              System.err.println(ex);
              throw ex;
          }
    
        }
    faccio un po di logging solo su getIstance() visto che è lei l'unica classe ad usare il costruttore Rbac.

    cmq ci stavo vicino alla soluzione

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.