Fixed locking issue with loading metadata
authortboudreau@netbeans.org
Mon, 06 Jun 2011 00:50:24 -0400
changeset 17498a04f35d4d4c5
parent 17497 dab01edfa9c0
child 17499 ea1d43042319
child 17545 c2c516fd96f1
Fixed locking issue with loading metadata
nodejs/manifest.mf
nodejs/src/org/netbeans/modules/nodejs/ProjectMetadataImpl.java
nodejs/src/org/netbeans/modules/nodejs/json/SimpleJSONParser.java
     1.1 --- a/nodejs/manifest.mf	Sun Jun 05 17:21:05 2011 -0400
     1.2 +++ b/nodejs/manifest.mf	Mon Jun 06 00:50:24 2011 -0400
     1.3 @@ -3,5 +3,5 @@
     1.4  OpenIDE-Module-Layer: org/netbeans/modules/nodejs/layer.xml
     1.5  OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/nodejs/Bundle.properties
     1.6  OpenIDE-Module-Requires: org.openide.modules.os.Unix
     1.7 -OpenIDE-Module-Specification-Version: 1.12
     1.8 +OpenIDE-Module-Specification-Version: 1.13
     1.9  
     2.1 --- a/nodejs/src/org/netbeans/modules/nodejs/ProjectMetadataImpl.java	Sun Jun 05 17:21:05 2011 -0400
     2.2 +++ b/nodejs/src/org/netbeans/modules/nodejs/ProjectMetadataImpl.java	Mon Jun 06 00:50:24 2011 -0400
     2.3 @@ -49,11 +49,11 @@
     2.4  import java.util.ArrayList;
     2.5  import java.util.Arrays;
     2.6  import java.util.Collections;
     2.7 -import java.util.HashMap;
     2.8  import java.util.Iterator;
     2.9  import java.util.LinkedHashMap;
    2.10  import java.util.List;
    2.11  import java.util.Map;
    2.12 +import java.util.concurrent.locks.ReentrantLock;
    2.13  import java.util.logging.Level;
    2.14  import java.util.logging.Logger;
    2.15  import org.netbeans.api.project.Project;
    2.16 @@ -67,6 +67,7 @@
    2.17  import org.openide.filesystems.FileAlreadyLockedException;
    2.18  import org.openide.filesystems.FileChangeAdapter;
    2.19  import org.openide.filesystems.FileEvent;
    2.20 +import org.openide.filesystems.FileLock;
    2.21  import org.openide.filesystems.FileObject;
    2.22  import org.openide.filesystems.FileSystem.AtomicAction;
    2.23  import org.openide.filesystems.FileUtil;
    2.24 @@ -106,7 +107,7 @@
    2.25              return toString(getMap().get(key));
    2.26          }
    2.27      }
    2.28 -    
    2.29 +
    2.30      public List<?> getValues(String key) {
    2.31          Object result = null;
    2.32          if (key.indexOf('.') > 0) {
    2.33 @@ -167,52 +168,69 @@
    2.34      private volatile Map<String, Object> map;
    2.35      private volatile boolean hasErrors;
    2.36      private volatile boolean listening;
    2.37 +    private final ReentrantLock lock = new ReentrantLock();
    2.38 +
    2.39 +    private Map<String, Object> load(FileObject fo) throws IOException {
    2.40 +        lock.lock();
    2.41 +        boolean err = false;
    2.42 +        try {
    2.43 +            synchronized (this) {
    2.44 +                if (map != null) {
    2.45 +                    return map;
    2.46 +                }
    2.47 +            }
    2.48 +            FileLock fileLock = fo.lock();
    2.49 +            try {
    2.50 +                SimpleJSONParser p = new SimpleJSONParser(true); //permissive mode - will parse as much as it can
    2.51 +                Map<String, Object> m = p.parse(fo);
    2.52 +                ProjectMetadataImpl.this.hasErrors = err = p.hasErrors();
    2.53 +                synchronized (this) {
    2.54 +                    map = Collections.synchronizedMap(m);
    2.55 +                    return map;
    2.56 +                }
    2.57 +            } catch (JsonException ex) {
    2.58 +                Logger.getLogger(ProjectMetadataImpl.class.getName()).log(Level.INFO,
    2.59 +                        "Bad package.json in " + fo.getPath(), ex);
    2.60 +                return new LinkedHashMap<String, Object>();
    2.61 +            } finally {
    2.62 +                fileLock.releaseLock();
    2.63 +            }
    2.64 +        } finally {
    2.65 +            lock.unlock();
    2.66 +            if (err) {
    2.67 +                StatusDisplayer.getDefault().setStatusText(NbBundle.getMessage(ProjectMetadataImpl.class, "ERROR_PARSING_PACKAGE_JSON", project.getLookup().lookup(ProjectInformation.class).getDisplayName()), 3);
    2.68 +            }
    2.69 +        }
    2.70 +    }
    2.71  
    2.72      private final Map<String, Object> getMap() {
    2.73 -        if (map != null) {
    2.74 +        Map<String, Object> result = map;
    2.75 +        if (result == null) {
    2.76              synchronized (this) {
    2.77 -                return map;
    2.78 +                result = map;
    2.79              }
    2.80          }
    2.81 -        final FileObject fo = project.getProjectDirectory().getFileObject("package.json");
    2.82 -        if (fo != null) {
    2.83 +        if (result == null) {
    2.84 +            final FileObject fo = project.getProjectDirectory().getFileObject("package.json");
    2.85 +            if (fo == null) {
    2.86 +                return new LinkedHashMap<String, Object>();
    2.87 +            }
    2.88 +            if (!listening) {
    2.89 +                listening = true;
    2.90 +                fo.addFileChangeListener(FileUtil.weakFileChangeListener(this, fo));
    2.91 +            }
    2.92              try {
    2.93 -                final boolean[] err = new boolean[1];
    2.94 -                Map<String, Object> m = ProjectManager.mutex().readAccess(new Mutex.ExceptionAction<Map<String, Object>>() {
    2.95 -
    2.96 -                    @Override
    2.97 -                    public Map<String, Object> run() throws Exception {
    2.98 -                        if (!listening) {
    2.99 -                            fo.addFileChangeListener(FileUtil.weakFileChangeListener(ProjectMetadataImpl.this, fo));
   2.100 -                            listening = true;
   2.101 -                        }
   2.102 -                        try {
   2.103 -                            SimpleJSONParser p = new SimpleJSONParser(true); //permissive mode - will parse as much as it can
   2.104 -                            Map<String, Object> m = p.parse(fo);
   2.105 -                            ProjectMetadataImpl.this.hasErrors = err[0] = p.hasErrors();
   2.106 -                            synchronized (ProjectMetadataImpl.this) {
   2.107 -                                map = Collections.synchronizedMap(m);
   2.108 -                            }
   2.109 -                            return m;
   2.110 -                        } catch (JsonException ex) {
   2.111 -                            throw new MutexException(ex);
   2.112 -                        } catch (IOException ex) {
   2.113 -                            throw new MutexException(ex);
   2.114 -                        }
   2.115 -                    }
   2.116 -                });
   2.117 -                if (err[0]) {
   2.118 -                    StatusDisplayer.getDefault().setStatusText(NbBundle.getMessage(ProjectMetadataImpl.class, "ERROR_PARSING_PACKAGE_JSON", project.getLookup().lookup(ProjectInformation.class).getDisplayName()), 3);
   2.119 +                result = load(fo);
   2.120 +                synchronized (this) {
   2.121 +                    map = result;
   2.122                  }
   2.123 -                return m;
   2.124 -            } catch (MutexException ex) {
   2.125 +            } catch (IOException ioe) {
   2.126                  Logger.getLogger(ProjectMetadataImpl.class.getName()).log(Level.INFO,
   2.127 -                        "Bad package.json in " + fo.getPath(), ex);
   2.128 +                        "Problems loading " + fo.getPath(), ioe);
   2.129 +                result = new LinkedHashMap<String,Object>();
   2.130              }
   2.131          }
   2.132 -        synchronized (this) {
   2.133 -            return map == null ? new LinkedHashMap<String, Object>() : map;
   2.134 -        }
   2.135 +        return result;
   2.136      }
   2.137      volatile int saveCount;
   2.138  
     3.1 --- a/nodejs/src/org/netbeans/modules/nodejs/json/SimpleJSONParser.java	Sun Jun 05 17:21:05 2011 -0400
     3.2 +++ b/nodejs/src/org/netbeans/modules/nodejs/json/SimpleJSONParser.java	Mon Jun 06 00:50:24 2011 -0400
     3.3 @@ -57,7 +57,6 @@
     3.4  import java.util.Stack;
     3.5  import java.util.logging.Level;
     3.6  import java.util.logging.Logger;
     3.7 -import org.openide.filesystems.FileLock;
     3.8  import org.openide.filesystems.FileObject;
     3.9  import org.openide.filesystems.FileUtil;
    3.10  import org.openide.util.Utilities;
    3.11 @@ -108,12 +107,7 @@
    3.12      }
    3.13  
    3.14      public Map<String, Object> parse(FileObject in) throws JsonException, IOException {
    3.15 -        FileLock lock = in.lock();
    3.16 -        try {
    3.17 -            return parse(in.asText());
    3.18 -        } finally {
    3.19 -            lock.releaseLock();
    3.20 -        }
    3.21 +        return parse(in.asText());
    3.22      }
    3.23  
    3.24      public Map<String, Object> parse(InputStream in) throws JsonException, IOException {