~ubuntu-branches/ubuntu/quantal/netbeans/quantal

« back to all changes in this revision

Viewing changes to core/settings/src/org/netbeans/modules/settings/InstanceProvider.java

  • Committer: Bazaar Package Importer
  • Author(s): Marek Slama
  • Date: 2008-01-29 14:11:22 UTC
  • Revision ID: james.westby@ubuntu.com-20080129141122-fnzjbo11ntghxfu7
Tags: upstream-6.0.1
ImportĀ upstreamĀ versionĀ 6.0.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 
3
 *
 
4
 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
 
5
 *
 
6
 * The contents of this file are subject to the terms of either the GNU
 
7
 * General Public License Version 2 only ("GPL") or the Common
 
8
 * Development and Distribution License("CDDL") (collectively, the
 
9
 * "License"). You may not use this file except in compliance with the
 
10
 * License. You can obtain a copy of the License at
 
11
 * http://www.netbeans.org/cddl-gplv2.html
 
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
 
13
 * specific language governing permissions and limitations under the
 
14
 * License.  When distributing the software, include this License Header
 
15
 * Notice in each file and include the License file at
 
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
 
17
 * particular file as subject to the "Classpath" exception as provided
 
18
 * by Sun in the GPL Version 2 section of the License file that
 
19
 * accompanied this code. If applicable, add the following below the
 
20
 * License Header, with the fields enclosed by brackets [] replaced by
 
21
 * your own identifying information:
 
22
 * "Portions Copyrighted [year] [name of copyright owner]"
 
23
 *
 
24
 * Contributor(s):
 
25
 *
 
26
 * The Original Software is NetBeans. The Initial Developer of the Original
 
27
 * Software is Sun Microsystems, Inc. Portions Copyright 2002-2003 Sun
 
28
 * Microsystems, Inc. All Rights Reserved.
 
29
 *
 
30
 * If you wish your version of this file to be governed by only the CDDL
 
31
 * or only the GPL Version 2, indicate your decision by adding
 
32
 * "[Contributor] elects to include this software in this distribution
 
33
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
 
34
 * single choice of license, a recipient has the option to distribute
 
35
 * your version of this file under either the CDDL, the GPL Version 2 or
 
36
 * to extend the choice of license to its licensees as provided above.
 
37
 * However, if you add GPL Version 2 code and therefore, elected the GPL
 
38
 * Version 2 license, then the option applies only if the new code is
 
39
 * made subject to such option by the copyright holder.
 
40
 */
 
41
 
 
42
package org.netbeans.modules.settings;
 
43
 
 
44
import java.beans.PropertyChangeEvent;
 
45
import java.lang.ref.SoftReference;
 
46
import java.io.IOException;
 
47
import java.util.logging.Level;
 
48
import java.util.logging.Logger;
 
49
import org.netbeans.modules.settings.convertors.SerialDataNode;
 
50
 
 
51
import org.openide.filesystems.FileObject;
 
52
import org.openide.filesystems.FileSystem;
 
53
import org.openide.filesystems.FileUtil;
 
54
import org.openide.nodes.Node;
 
55
import org.openide.util.Lookup;
 
56
import org.openide.cookies.SaveCookie;
 
57
import org.openide.cookies.InstanceCookie;
 
58
 
 
59
import org.netbeans.spi.settings.Convertor;
 
60
import org.openide.util.Exceptions;
 
61
 
 
62
/** Provides the Lookup content.
 
63
 *
 
64
 * @author  Jan Pokorsky
 
65
 */
 
66
final class InstanceProvider extends org.openide.filesystems.FileChangeAdapter
 
67
implements java.beans.PropertyChangeListener, FileSystem.AtomicAction {
 
68
    /** Logging for events in this class */
 
69
    private static final Logger LOG = Logger.getLogger(InstanceProvider.class.getName()); // NOI18N
 
70
    
 
71
    /** container handling objects provided by {@link #lookup} */
 
72
    private final org.openide.util.lookup.InstanceContent lkpContent;
 
73
    /** container exposing setting to the outside world */
 
74
    private final org.openide.util.Lookup lookup;
 
75
    private final org.openide.loaders.DataObject dobj;
 
76
    private final FileObject settingFO;
 
77
    private final FileObject providerFO;
 
78
    private final NodeConvertor node;
 
79
    //save support
 
80
    private SaveSupport saver;
 
81
    private SaveCookie scCache;
 
82
    private boolean wasReportedProblem = false;
 
83
    private java.util.Set<String> instanceOfSet;
 
84
    private String instanceClassName;
 
85
    /** lock used to sync read/write operations for .settings file */
 
86
    final Object READWRITE_LOCK = new Object();
 
87
    
 
88
    /** Creates a new instance of InstanceCooikeProvider */
 
89
    public InstanceProvider(org.openide.loaders.DataObject dobj, FileObject providerFO) {
 
90
//        System.out.println("new IP: " + dobj);
 
91
        this.settingFO = dobj.getPrimaryFile();
 
92
        this.providerFO = providerFO;
 
93
        this.dobj = dobj;
 
94
        
 
95
        settingFO.addFileChangeListener(
 
96
            FileUtil.weakFileChangeListener(this, settingFO));
 
97
        
 
98
        lkpContent = new org.openide.util.lookup.InstanceContent();
 
99
        lkpContent.add(createInstance(null));
 
100
        node = new NodeConvertor();
 
101
        lkpContent.add(this, node);
 
102
        lookup = new org.openide.util.lookup.AbstractLookup(lkpContent);
 
103
    }
 
104
    
 
105
    /** provides content like InstanceCookie, SaveCokie */
 
106
    public Lookup getLookup() {
 
107
        return lookup;
 
108
    }
 
109
    /** file contanining various attributes related to setting like convertor
 
110
     * class, ...
 
111
     */
 
112
    FileObject getProvider() {
 
113
        return providerFO;
 
114
    }
 
115
    /** file containing a persisted setting object */
 
116
    FileObject getFile () {
 
117
        return settingFO;
 
118
    }
 
119
    
 
120
    org.openide.loaders.DataObject getDataObject() {
 
121
        return dobj;
 
122
    }
 
123
    
 
124
    public void propertyChange(PropertyChangeEvent evt) {
 
125
        if (evt == null) return;
 
126
 
 
127
        String name = evt.getPropertyName();
 
128
        if (name == null)
 
129
            return;
 
130
        else if (name == SaveSupport.PROP_SAVE)
 
131
            provideSaveCookie();
 
132
        else if (name == SaveSupport.PROP_FILE_CHANGED) {
 
133
            synchronized (this) {
 
134
                instanceOfSet = null;
 
135
            }
 
136
            instanceCookieChanged(null);
 
137
        }
 
138
    }
 
139
    
 
140
    /** process events coming from the file object*/
 
141
    public void fileChanged(org.openide.filesystems.FileEvent fe) {
 
142
        if (saver != null && fe.firedFrom((FileSystem.AtomicAction) saver.getSaveCookie())) return;
 
143
        propertyChange(new PropertyChangeEvent(this, SaveSupport.PROP_FILE_CHANGED, null, null));
 
144
    }
 
145
  
 
146
    public void fileDeleted(org.openide.filesystems.FileEvent fe) {
 
147
        if (saver != null && fe.firedFrom((FileSystem.AtomicAction) saver.getSaveCookie())) return;
 
148
        releaseInstance();
 
149
    }
 
150
    
 
151
    
 
152
    /** allow to listen on changes of the object inst; should be called when
 
153
     * new instance is created */
 
154
    private synchronized void attachToInstance(Object inst) {
 
155
        if (saver != null) {
 
156
            saver.removePropertyChangeListener(this);
 
157
            getScheduledRequest().forceToFinish();
 
158
        }
 
159
        saver = createSaveSupport(inst);
 
160
        saver.addPropertyChangeListener(this);
 
161
    }
 
162
    
 
163
    /** create own InstanceCookie implementation */
 
164
    private InstanceCookie.Of createInstance(Object inst) {
 
165
        return new InstanceCookieImpl(inst);
 
166
    }
 
167
    
 
168
    /** method provides a support storing the setting */
 
169
    private SaveSupport createSaveSupport(Object inst) {
 
170
        return new SaveSupport(this, inst);
 
171
    }
 
172
    
 
173
    private void provideSaveCookie() {
 
174
        SaveCookie scNew = saver.getSaveCookie();
 
175
        if (scCache != null) {
 
176
            if (!saver.isChanged()) {
 
177
                if (LOG.isLoggable(Level.FINE)) LOG.fine("remove save cookie: " + dobj); // NOI18N
 
178
                lkpContent.remove(scCache);
 
179
                scCache = null;
 
180
                return;
 
181
            }
 
182
        } else {
 
183
            if (saver.isChanged()) {
 
184
                scCache = scNew;
 
185
                if (LOG.isLoggable(Level.FINE)) LOG.fine("add save cookie: " + dobj + " cookie: " + scNew); // NOI18N
 
186
                lkpContent.add(scNew);
 
187
                return;
 
188
            }
 
189
        }
 
190
    }
 
191
    
 
192
    private void releaseInstance() {
 
193
        SaveSupport _saver = saver;
 
194
        if (_saver != null) {
 
195
            _saver.removePropertyChangeListener(this);
 
196
        }
 
197
        
 
198
        if (scCache != null) {
 
199
            if (LOG.isLoggable(Level.FINE)) LOG.fine("release instance and remove save cookie: " + dobj); // NOI18N
 
200
            lkpContent.remove(scCache);
 
201
            getScheduledRequest().cancel();
 
202
            scCache = null;
 
203
        }
 
204
        
 
205
        lkpContent.remove(this, node);
 
206
    }
 
207
    
 
208
    private void instanceCookieChanged(Object inst) {
 
209
        if (LOG.isLoggable(Level.FINE)) LOG.fine("instanceCookieChanged: " + dobj + " inst: " + inst); // NOI18N
 
210
        releaseInstance();
 
211
        
 
212
        lkpContent.add(this, node);
 
213
        
 
214
        Object ic = lookup.lookup(InstanceCookie.class);
 
215
        lkpContent.remove(ic);
 
216
 
 
217
        Object newCookie = createInstance(inst);
 
218
        lkpContent.add(newCookie);
 
219
        if (LOG.isLoggable(Level.FINE)) LOG.fine("cookie replaced: " + dobj + " old: " + ic + " new: " + newCookie); // NOI18N
 
220
    }
 
221
    
 
222
    private Convertor convertor;
 
223
    
 
224
    /** find out  proper convertor */
 
225
    Convertor getConvertor() throws IOException {
 
226
        if (convertor == null) {
 
227
            Object attrb = providerFO.getAttribute(Env.EA_CONVERTOR);
 
228
            if (attrb == null || !(attrb instanceof Convertor)) {
 
229
                throw new IOException("cannot create convertor: " + attrb + ", provider:" +providerFO); //NOI18N
 
230
            }
 
231
            convertor = (Convertor) attrb;
 
232
        }
 
233
        return convertor;
 
234
    }
 
235
    
 
236
    /** find out setting object class name */
 
237
    private synchronized String getInstanceClassName() {
 
238
        if (instanceClassName == null) {
 
239
            Object name = providerFO.getAttribute(Env.EA_INSTANCE_CLASS_NAME);
 
240
            if (name != null && name instanceof String) {
 
241
                instanceClassName = org.openide.util.Utilities.translate((String) name);
 
242
            } else {
 
243
                instanceClassName = null;
 
244
            }
 
245
        }
 
246
        return instanceClassName;
 
247
    }
 
248
    
 
249
    public String toString() {
 
250
        return this.getClass().getName() + '@' +
 
251
            Integer.toHexString(System.identityHashCode(this)) +
 
252
            '[' + getDataObject() + ", " + getProvider() + ']';
 
253
    }
 
254
    
 
255
    
 
256
    /** called by ScheduledRequest in order to perform the request */
 
257
    public void run() throws IOException {
 
258
        saver.writeDown();
 
259
    }
 
260
    
 
261
    /** scheduled request to store setting */
 
262
    private ScheduledRequest request;
 
263
    
 
264
    /** get the scheduled request to store setting */
 
265
    synchronized ScheduledRequest getScheduledRequest() {
 
266
        if (request == null) {
 
267
            request = new ScheduledRequest(settingFO, this);
 
268
        }
 
269
        return request;
 
270
    }
 
271
    
 
272
    /////////////////////////////////////////////////////////////////////////
 
273
    // InstanceCookieImpl
 
274
    /////////////////////////////////////////////////////////////////////////
 
275
    
 
276
    /** InstanceCookie implementation. */
 
277
    final class InstanceCookieImpl implements InstanceCookie.Of {
 
278
        private SoftReference<Object> cachedInstance;// = new SoftReference(null);
 
279
        
 
280
        public InstanceCookieImpl(Object inst) {
 
281
            setCachedInstance(inst);
 
282
        }
 
283
        
 
284
        public Class instanceClass() throws IOException, ClassNotFoundException {
 
285
            String name = getInstanceClassName();
 
286
            if (name == null) {
 
287
                return instanceCreate().getClass();
 
288
            } else {
 
289
                return ((ClassLoader)Lookup.getDefault().lookup(ClassLoader.class)).loadClass(name);
 
290
            }
 
291
        }
 
292
 
 
293
        public Object instanceCreate() throws java.io.IOException, ClassNotFoundException {
 
294
            Object inst;
 
295
            
 
296
            synchronized (this) {
 
297
                inst = getCachedInstance();
 
298
                if (inst != null) return inst;
 
299
            }
 
300
            
 
301
            try {
 
302
                synchronized (READWRITE_LOCK) {
 
303
                    java.io.Reader r = ContextProvider.createReaderContextProvider(
 
304
                        new java.io.InputStreamReader(settingFO.getInputStream(),"UTF-8"), //NOI18N
 
305
                        getFile()
 
306
                    );
 
307
                    inst = getConvertor().read(r);
 
308
                }
 
309
            } catch (IOException ex) {
 
310
                throw (IOException) Exceptions.attachLocalizedMessage(ex,
 
311
                                                  InstanceProvider.this.toString());
 
312
            } catch (ClassNotFoundException ex) {
 
313
                throw (ClassNotFoundException) Exceptions.attachLocalizedMessage(ex,
 
314
                                                  InstanceProvider.this.toString());
 
315
            }
 
316
            
 
317
            synchronized (this) {
 
318
                Object existing = getCachedInstance();
 
319
                if (existing != null) return existing;
 
320
                setCachedInstance(inst);
 
321
            }
 
322
            attachToInstance(inst);
 
323
            
 
324
            return inst;
 
325
        }
 
326
 
 
327
        public String instanceName() {
 
328
            String name = getInstanceClassName();
 
329
            if (name != null) return name;
 
330
            
 
331
            Exception e = null;
 
332
            try {
 
333
                return instanceClass().getName();
 
334
            } catch (IOException ex) {
 
335
                e = ex;
 
336
            } catch (ClassNotFoundException ex) {
 
337
                e = ex;
 
338
            }
 
339
            if (e != null && !wasReportedProblem) {
 
340
                wasReportedProblem = true;
 
341
                Exceptions.attachLocalizedMessage(e, dobj.toString());
 
342
                Logger.getLogger(InstanceProvider.class.getName()).log(Level.WARNING, null, e);
 
343
            }
 
344
            return "Unknown"; // NOI18N
 
345
        }
 
346
 
 
347
        public boolean instanceOf(Class<?> type) {
 
348
            synchronized (InstanceProvider.this) {
 
349
                if (instanceOfSet == null) {
 
350
                    instanceOfSet = Env.parseAttribute(providerFO.getAttribute(Env.EA_INSTANCE_OF));
 
351
                    java.util.Iterator<String> it = instanceOfSet.iterator();
 
352
                    instanceOfSet = new java.util.HashSet<String>(instanceOfSet.size() * 5 / 4);
 
353
                    while (it.hasNext()) {
 
354
                        instanceOfSet.add(org.openide.util.Utilities.translate(it.next()));
 
355
                    }
 
356
                }
 
357
            }
 
358
            if (instanceOfSet.isEmpty()) {
 
359
                Exception e = null;
 
360
                try {
 
361
                    return type.isAssignableFrom(instanceClass());
 
362
                } catch (IOException ex) {
 
363
                    e = ex;
 
364
                } catch (ClassNotFoundException ex) {
 
365
                    e = ex;
 
366
                }
 
367
                if (e != null && !wasReportedProblem) {
 
368
                    wasReportedProblem = true;
 
369
                    Exceptions.attachLocalizedMessage(e, dobj.toString());
 
370
                    Logger.getLogger(InstanceProvider.class.getName()).log(Level.WARNING, null, e);
 
371
                }
 
372
                return false;
 
373
            } else {
 
374
                return instanceOfSet.contains(type.getName());
 
375
            }
 
376
        }
 
377
        
 
378
        // called by InstanceDataObject to set new object
 
379
        public void setInstance(Object inst, boolean save) throws IOException {
 
380
            instanceCookieChanged(inst);
 
381
            if (inst != null) {
 
382
                attachToInstance(inst);
 
383
                if (save) getScheduledRequest().runAndWait();
 
384
            }
 
385
        }
 
386
    
 
387
        private Object getCachedInstance() {
 
388
            return cachedInstance.get();
 
389
        }
 
390
        private void setCachedInstance(Object inst) {
 
391
            cachedInstance = new SoftReference<Object>(inst);
 
392
        }
 
393
    }
 
394
    
 
395
////////////////////////////////////////////////////////////////////////////
 
396
// NodeConvertor
 
397
////////////////////////////////////////////////////////////////////////////
 
398
    
 
399
    /** allow to postpone the node creation */
 
400
    private static final class NodeConvertor 
 
401
            implements org.openide.util.lookup.InstanceContent.Convertor<InstanceProvider, Node> {
 
402
        NodeConvertor() {}
 
403
     
 
404
        public Node convert(InstanceProvider o) {
 
405
            return new SerialDataNode(o.getDataObject());
 
406
        }
 
407
     
 
408
        public Class<Node> type(InstanceProvider o) {
 
409
            return Node.class;
 
410
        }
 
411
     
 
412
        public String id(InstanceProvider o) {
 
413
            // Generally irrelevant in this context.
 
414
            return o.toString();
 
415
        }
 
416
     
 
417
        public String displayName(InstanceProvider o) {
 
418
            // Again, irrelevant here.
 
419
            return o.toString();
 
420
        }
 
421
     
 
422
    }
 
423
}