| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| package org.netbeans.modules.ant.freeform; |
| |
| import java.beans.PropertyChangeEvent; |
| import java.beans.PropertyChangeListener; |
| import java.beans.PropertyChangeSupport; |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import org.netbeans.spi.project.support.ant.AntProjectEvent; |
| import org.netbeans.spi.project.support.ant.AntProjectListener; |
| import org.netbeans.spi.project.support.ant.PropertyEvaluator; |
| import org.netbeans.spi.project.support.ant.PropertyProvider; |
| import org.netbeans.spi.project.support.ant.PropertyUtils; |
| import org.openide.ErrorManager; |
| import org.openide.util.Parameters; |
| import org.openide.xml.XMLUtil; |
| import org.w3c.dom.Element; |
| |
| /** |
| * Manages property evaluation for the freeform project. |
| * Refreshes properties if (1) project.xml changes; (2) some *.properties changes. |
| * @author Jesse Glick |
| */ |
| final class FreeformEvaluator implements PropertyEvaluator, AntProjectListener, PropertyChangeListener { |
| |
| private final FreeformProject project; |
| private PropertyEvaluator delegate; |
| private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); |
| private final Set<PropertyEvaluator> intermediateEvaluators = new HashSet<PropertyEvaluator>(); |
| private final Object privateLock = new Object(); |
| |
| public FreeformEvaluator(FreeformProject project) throws IOException { |
| this.project = project; |
| init(); |
| project.helper().addAntProjectListener(this); |
| } |
| |
| private void init() throws IOException { |
| PropertyEvaluator newDelegate = initEval(); |
| synchronized (privateLock) { |
| if (delegate != null) { |
| delegate.removePropertyChangeListener(this); |
| } |
| newDelegate.addPropertyChangeListener(this); |
| delegate = newDelegate; |
| } |
| if (org.netbeans.modules.ant.freeform.Util.err.isLoggable(ErrorManager.INFORMATIONAL)) { |
| org.netbeans.modules.ant.freeform.Util.err.log("properties for " + project.getProjectDirectory() + ": " + delegate.getProperties()); |
| } |
| } |
| |
| private PropertyEvaluator initEval() throws IOException { |
| // Stop listening to old intermediate evaluators. |
| Iterator<PropertyEvaluator> ieIt = intermediateEvaluators.iterator(); |
| while (ieIt.hasNext()) { |
| ieIt.next().removePropertyChangeListener(this); |
| ieIt.remove(); |
| } |
| PropertyProvider preprovider = project.helper().getStockPropertyPreprovider(); |
| List<PropertyProvider> defs = new ArrayList<PropertyProvider>(); |
| Element genldata = project.getPrimaryConfigurationData(); |
| Element properties = XMLUtil.findElement(genldata, "properties", FreeformProjectType.NS_GENERAL); // NOI18N |
| if (properties != null) { |
| for (Element e : XMLUtil.findSubElements(properties)) { |
| if (e.getLocalName().equals("property")) { // NOI18N |
| String val = XMLUtil.findText(e); |
| if (val == null) { |
| val = ""; |
| } |
| defs.add(PropertyUtils.fixedPropertyProvider(Collections.singletonMap(e.getAttribute("name"), val))); // NOI18N |
| } else { |
| assert e.getLocalName().equals("property-file") : e; |
| String fname = XMLUtil.findText(e); |
| if (fname.contains("${")) { // NOI18N |
| // Tricky (#48230): need to listen to changes in the location of the file as well as its contents. |
| PropertyEvaluator intermediate = PropertyUtils.sequentialPropertyEvaluator(preprovider, defs.toArray(new PropertyProvider[defs.size()])); |
| fname = intermediate.evaluate(fname); |
| if (fname == null) { |
| continue; |
| } |
| // Listen to changes in it, too. |
| intermediate.addPropertyChangeListener(this); |
| intermediateEvaluators.add(intermediate); |
| } |
| defs.add(PropertyUtils.propertiesFilePropertyProvider(project.helper().resolveFile(fname))); |
| } |
| } |
| } |
| return PropertyUtils.sequentialPropertyEvaluator(preprovider, defs.toArray(new PropertyProvider[defs.size()])); |
| } |
| |
| public String getProperty(String prop) { |
| return delegate.getProperty(prop); |
| } |
| |
| public String evaluate(String text) { |
| return delegate.evaluate(text); |
| } |
| |
| public Map<String,String> getProperties() { |
| return delegate.getProperties(); |
| } |
| |
| public void addPropertyChangeListener(PropertyChangeListener listener) { |
| Parameters.notNull("listener", listener); // NOI18N |
| pcs.addPropertyChangeListener(listener); |
| } |
| |
| public void removePropertyChangeListener(PropertyChangeListener listener) { |
| Parameters.notNull("listener", listener); // NOI18N |
| pcs.removePropertyChangeListener(listener); |
| } |
| |
| public void configurationXmlChanged(AntProjectEvent ev) { |
| fireAnyChange(); |
| } |
| |
| private void fireAnyChange() { |
| try { |
| init(); |
| } catch (IOException ex) { |
| ErrorManager.getDefault().notify(ErrorManager.ERROR, ex); |
| } catch (RuntimeException ex) { |
| // Something else? E.g. IAE when parsing <properties> block. |
| ErrorManager.getDefault().notify(ErrorManager.ERROR, ex); |
| } |
| pcs.firePropertyChange(null, null, null); |
| } |
| |
| public void propertiesChanged(AntProjectEvent ev) { |
| // ignore |
| } |
| |
| public void propertyChange(PropertyChangeEvent propertyChangeEvent) { |
| Object source = propertyChangeEvent.getSource(); |
| assert source instanceof PropertyEvaluator : source; |
| if (intermediateEvaluators.contains(source)) { |
| // A <property-file> may have changed location. Generally need to rebuild the list of definers. |
| fireAnyChange(); |
| } else { |
| // If a properties file changes on disk, we refire that from the delegate. |
| assert source == delegate : "Got change from " + source + " rather than current delegate " + delegate; |
| pcs.firePropertyChange(propertyChangeEvent.getPropertyName(), null, null); |
| } |
| } |
| |
| } |