1 19 20 package org.netbeans.spi.project.support.ant; 21 22 import java.io.ByteArrayOutputStream ; 23 import java.io.File ; 24 import java.io.IOException ; 25 import java.io.InputStream ; 26 import java.io.OutputStream ; 27 import java.util.ArrayList ; 28 import java.util.Collections ; 29 import java.util.HashMap ; 30 import java.util.List ; 31 import java.util.Map ; 32 import java.util.Properties ; 33 import javax.swing.event.ChangeEvent ; 34 import javax.swing.event.ChangeListener ; 35 import org.netbeans.api.project.ProjectManager; 36 import org.netbeans.modules.project.ant.FileChangeSupport; 37 import org.netbeans.modules.project.ant.FileChangeSupportEvent; 38 import org.netbeans.modules.project.ant.FileChangeSupportListener; 39 import org.netbeans.modules.project.ant.UserQuestionHandler; 40 import org.openide.ErrorManager; 41 import org.openide.filesystems.FileLock; 42 import org.openide.filesystems.FileObject; 43 import org.openide.filesystems.FileSystem; 44 import org.openide.filesystems.FileUtil; 45 import org.openide.modules.InstalledFileLocator; 46 import org.openide.util.Mutex; 47 import org.openide.util.NbCollections; 48 import org.openide.util.RequestProcessor; 49 import org.openide.util.UserQuestionException; 50 import org.openide.util.Utilities; 51 52 56 final class ProjectProperties { 57 58 59 private final AntProjectHelper helper; 60 61 66 private final Map <String ,PP> properties = new HashMap <String ,PP>(); 67 68 69 private PropertyProvider stockPropertyPreprovider = null; 70 71 72 private PropertyEvaluator standardPropertyEvaluator = null; 73 74 78 public ProjectProperties(AntProjectHelper helper) { 79 this.helper = helper; 80 } 81 82 86 public void clear() { 87 properties.clear(); 88 } 89 90 95 public EditableProperties getProperties(String path) { 96 EditableProperties ep = getPP(path).getEditablePropertiesOrNull(); 97 if (ep != null) { 98 return ep.cloneProperties(); 99 } else { 100 return new EditableProperties(true); 101 } 102 } 103 104 110 public boolean putProperties(String path, EditableProperties props) { 111 return getPP(path).put(props); 112 } 113 114 119 public FileLock write(String path) throws IOException { 120 assert properties.containsKey(path); 121 return getPP(path).write(); 122 } 123 124 128 public PropertyProvider getPropertyProvider(String path) { 129 return getPP(path); 130 } 131 132 private PP getPP(String path) { 133 PP pp = properties.get(path); 134 if (pp == null) { 135 pp = new PP(path, helper); 136 properties.put(path, pp); 137 } 138 return pp; 139 } 140 141 private static final class PP implements PropertyProvider, FileChangeSupportListener { 142 143 private static final RequestProcessor RP = new RequestProcessor("ProjectProperties.PP.RP"); 145 148 private final String path; 149 private final AntProjectHelper helper; 150 private EditableProperties properties = null; 151 private boolean loaded = false; 152 private final List <ChangeListener > listeners = new ArrayList <ChangeListener >(); 153 private boolean writing = false; 154 155 public PP(String path, AntProjectHelper helper) { 156 this.path = path; 157 this.helper = helper; 158 FileChangeSupport.DEFAULT.addListener(this, new File (FileUtil.toFile(dir()), path.replace('/', File.separatorChar))); 159 } 160 161 private FileObject dir() { 162 return helper.getProjectDirectory(); 163 } 164 165 public EditableProperties getEditablePropertiesOrNull() { 166 if (!loaded) { 167 properties = null; 168 FileObject fo = dir().getFileObject(path); 169 if (fo != null) { 170 try { 171 EditableProperties p; 172 InputStream is = fo.getInputStream(); 173 try { 174 p = new EditableProperties(true); 175 p.load(is); 176 } finally { 177 is.close(); 178 } 179 properties = p; 180 } catch (IOException e) { 181 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e); 182 } 183 } 184 loaded = true; 185 } 186 return properties; 187 } 188 189 public boolean put(EditableProperties nue) { 190 loaded = true; 191 boolean modifying = !Utilities.compareObjects(nue, properties); 192 if (modifying) { 193 if (nue != null) { 194 properties = nue.cloneProperties(); 195 } else { 196 properties = null; 197 } 198 fireChange(); 199 } 200 return modifying; 201 } 202 203 public FileLock write() throws IOException { 204 assert loaded; 205 final FileObject f = dir().getFileObject(path); 206 assert !writing; 207 final FileLock[] _lock = new FileLock[1]; 208 writing = true; 209 try { 210 if (properties != null) { 211 dir().getFileSystem().runAtomicAction(new FileSystem.AtomicAction() { 216 public void run() throws IOException { 217 final FileObject _f; 218 if (f == null) { 219 _f = FileUtil.createData(dir(), path); 220 assert _f != null : "FU.cD must not return null; called on " + dir() + " + " + path; } else { 222 _f = f; 223 } 224 ByteArrayOutputStream baos = new ByteArrayOutputStream (); 225 properties.store(baos); 226 final byte[] data = baos.toByteArray(); 227 try { 228 _lock[0] = _f.lock(); OutputStream os = _f.getOutputStream(_lock[0]); 230 try { 231 os.write(data); 232 } finally { 233 os.close(); 234 } 235 } catch (UserQuestionException uqe) { helper.needPendingHook(); 237 UserQuestionHandler.handle(uqe, new UserQuestionHandler.Callback() { 238 public void accepted() { 239 assert !writing; 241 writing = true; 242 try { 243 FileLock lock = _f.lock(); 244 try { 245 OutputStream os = _f.getOutputStream(lock); 246 try { 247 os.write(data); 248 } finally { 249 os.close(); 250 } 251 } finally { 252 lock.releaseLock(); 253 } 254 helper.maybeCallPendingHook(); 255 } catch (IOException e) { 256 ErrorManager.getDefault().notify(e); 258 reload(); 259 } finally { 260 writing = false; 261 } 262 } 263 public void denied() { 264 reload(); 265 } 266 public void error(IOException e) { 267 ErrorManager.getDefault().notify(e); 268 reload(); 269 } 270 private void reload() { 271 helper.cancelPendingHook(); 272 diskChange(); 274 } 275 }); 276 } 277 } 278 }); 279 } else { 280 if (f != null) { 282 f.delete(); 283 } 284 } 285 } catch (IOException e) { 286 if (_lock[0] != null) { 287 _lock[0].releaseLock(); 289 } 290 throw e; 291 } finally { 292 writing = false; 293 } 294 return _lock[0]; 295 } 296 297 public Map <String ,String > getProperties() { 298 Map <String ,String > props = getEditablePropertiesOrNull(); 299 if (props != null) { 300 return Collections.unmodifiableMap(props); 301 } else { 302 return Collections.emptyMap(); 303 } 304 } 305 306 public synchronized void addChangeListener(ChangeListener l) { 307 listeners.add(l); 308 } 309 310 public synchronized void removeChangeListener(ChangeListener l) { 311 listeners.remove(l); 312 } 313 314 private void fireChange() { 315 final ChangeListener [] ls; 316 synchronized (this) { 317 if (listeners.isEmpty()) { 318 return; 319 } 320 ls = listeners.toArray(new ChangeListener [listeners.size()]); 321 } 322 final ChangeEvent ev = new ChangeEvent (this); 323 final Mutex.Action<Void > action = new Mutex.Action<Void >() { 324 public Void run() { 325 for (ChangeListener l : ls) { 326 l.stateChanged(ev); 327 } 328 return null; 329 } 330 }; 331 if (ProjectManager.mutex().isWriteAccess()) { 332 ProjectManager.mutex().readAccess(action); 334 } else if (ProjectManager.mutex().isReadAccess()) { 335 action.run(); 337 } else { 338 RP.post(new Runnable () { 340 public void run() { 341 ProjectManager.mutex().readAccess(action); 342 } 343 }); 344 } 345 } 346 347 private void diskChange() { 348 if (!writing) { 350 loaded = false; 351 } 352 fireChange(); 353 if (!writing) { 354 helper.fireExternalChange(path); 355 } 356 } 357 358 public void fileCreated(FileChangeSupportEvent event) { 359 diskChange(); 360 } 361 362 public void fileDeleted(FileChangeSupportEvent event) { 363 diskChange(); 364 } 365 366 public void fileModified(FileChangeSupportEvent event) { 367 diskChange(); 368 } 369 370 } 371 372 375 public PropertyProvider getStockPropertyPreprovider() { 376 if (stockPropertyPreprovider == null) { 377 Map <String ,String > m; 378 Properties p = System.getProperties(); 379 synchronized (p) { 380 m = NbCollections.checkedMapByCopy(p, String .class, String .class, false); 381 } 382 m.put("basedir", FileUtil.toFile(helper.getProjectDirectory()).getAbsolutePath()); File antJar = InstalledFileLocator.getDefault().locate("ant/lib/ant.jar", "org.apache.tools.ant.module", false); if (antJar != null) { 385 File antHome = antJar.getParentFile().getParentFile(); 386 m.put("ant.home", antHome.getAbsolutePath()); } 388 stockPropertyPreprovider = PropertyUtils.fixedPropertyProvider(m); 389 } 390 return stockPropertyPreprovider; 391 } 392 393 396 public PropertyEvaluator getStandardPropertyEvaluator() { 397 if (standardPropertyEvaluator == null) { 398 PropertyEvaluator findUserPropertiesFile = PropertyUtils.sequentialPropertyEvaluator( 399 getStockPropertyPreprovider(), 400 getPropertyProvider(AntProjectHelper.PRIVATE_PROPERTIES_PATH)); 401 PropertyProvider globalProperties = PropertyUtils.userPropertiesProvider(findUserPropertiesFile, 402 "user.properties.file", FileUtil.toFile(helper.getProjectDirectory())); standardPropertyEvaluator = PropertyUtils.sequentialPropertyEvaluator( 404 getStockPropertyPreprovider(), 405 getPropertyProvider(AntProjectHelper.PRIVATE_PROPERTIES_PATH), 406 globalProperties, 407 getPropertyProvider(AntProjectHelper.PROJECT_PROPERTIES_PATH)); 408 } 409 return standardPropertyEvaluator; 410 } 411 412 } 413 | Popular Tags |