001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.java.api.common.ant;
043:
044: import java.io.IOException;
045: import org.openide.util.Exceptions;
046: import org.w3c.dom.Element;
047: import org.openide.util.Mutex;
048: import org.netbeans.api.project.ProjectManager;
049: import org.netbeans.spi.project.support.ant.AntProjectHelper;
050: import org.netbeans.spi.project.support.ant.EditableProperties;
051: import org.openide.util.MutexException;
052: import org.openide.util.Parameters;
053:
054: /**
055: * Proxy for the {@link AntProjectHelper} which defers the update of the project metadata
056: * to explicit user action. Caller has to provide implementation of {@link UpdateProject}
057: * which takes care of updating project itself.
058: * @author Tomas Zezula, Tomas Mysik
059: * @see UpdateImplementation
060: */
061: public final class UpdateHelper {
062:
063: private final UpdateImplementation updateProject;
064: private final AntProjectHelper helper;
065:
066: /**
067: * Create new {@link UpdateHelper}.
068: * @param updateProject {@link UpdateImplementation} which takes care of updating project itself.
069: * @param helper {@link AntProjectHelper} to be proxied.
070: */
071: public UpdateHelper(UpdateImplementation updateProject,
072: AntProjectHelper helper) {
073: Parameters.notNull("updateProject", updateProject); // NOI18N
074: Parameters.notNull("helper", helper); // NOI18N
075:
076: this .updateProject = updateProject;
077: this .helper = helper;
078: }
079:
080: /**
081: * In the case that the project is of current version or the properties
082: * are not {@link AntProjectHelper#PROJECT_PROPERTIES_PATH} it calls
083: * {@link AntProjectHelper#getProperties(String)} otherwise it asks for updated project properties.
084: * @param path a relative URI in the project directory.
085: * @return a set of properties.
086: */
087: public EditableProperties getProperties(final String path) {
088: return ProjectManager.mutex().readAccess(
089: new Mutex.Action<EditableProperties>() {
090: public EditableProperties run() {
091: if (!isCurrent()
092: && AntProjectHelper.PROJECT_PROPERTIES_PATH
093: .equals(path)) {
094: // only project properties were changed
095: return updateProject
096: .getUpdatedProjectProperties();
097: }
098: return helper.getProperties(path);
099: }
100: });
101: }
102:
103: /**
104: * In the case that the project is of current version or the properties
105: * are not {@link AntProjectHelper#PROJECT_PROPERTIES_PATH} it calls
106: * {@link AntProjectHelper#putProperties(String, EditableProperties)} otherwise it asks to update project.
107: * If the project can be updated, it does the update and calls
108: * {@link AntProjectHelper#putProperties(String, EditableProperties)}.
109: * @param path a relative URI in the project directory.
110: * @param props a set of properties.
111: */
112: public void putProperties(final String path,
113: final EditableProperties props) {
114: ProjectManager.mutex().writeAccess(new Runnable() {
115: public void run() {
116: if (isCurrent()
117: || !AntProjectHelper.PROJECT_PROPERTIES_PATH
118: .equals(path)) {
119: // only project props should cause update
120: helper.putProperties(path, props);
121: } else if (updateProject.canUpdate()) {
122: try {
123: updateProject.saveUpdate(props);
124: helper.putProperties(path, props);
125: } catch (IOException ioe) {
126: Exceptions.printStackTrace(ioe);
127: }
128: }
129: }
130: });
131: }
132:
133: /**
134: * In the case that the project is of current version or shared is <code>false</code> it delegates to
135: * {@link AntProjectHelper#getPrimaryConfigurationData(boolean)}.
136: * Otherwise it creates an in memory update of shared configuration data and returns it.
137: * @param shared if <code>true</code>, refers to <e>project.xml</e>, else refers to
138: * <e>private.xml</e>.
139: * @return the configuration data that is available.
140: */
141: public Element getPrimaryConfigurationData(final boolean shared) {
142: return ProjectManager.mutex().readAccess(
143: new Mutex.Action<Element>() {
144: public Element run() {
145: if (!shared || isCurrent()) { // only shared props should cause update
146: return helper
147: .getPrimaryConfigurationData(shared);
148: }
149: return updateProject
150: .getUpdatedSharedConfigurationData();
151: }
152: });
153: }
154:
155: /**
156: * In the case that the project is of current version or shared is <code>false</code> it calls
157: * {@link AntProjectHelper#putPrimaryConfigurationData(Element, boolean)}.
158: * Otherwise the project can be updated, it does the update and calls
159: * {@link AntProjectHelper#putPrimaryConfigurationData(Element, boolean)}.
160: * @param element the configuration data
161: * @param shared if true, refers to <code>project.xml</code>, else refers to
162: * <code>private.xml</code>
163: */
164: public void putPrimaryConfigurationData(final Element element,
165: final boolean shared) {
166: ProjectManager.mutex().writeAccess(new Runnable() {
167: public void run() {
168: if (!shared || isCurrent()) {
169: helper.putPrimaryConfigurationData(element, shared);
170: } else if (updateProject.canUpdate()) {
171: try {
172: updateProject.saveUpdate(null);
173: helper.putPrimaryConfigurationData(element,
174: shared);
175: } catch (IOException ioe) {
176: Exceptions.printStackTrace(ioe);
177: }
178: }
179: }
180: });
181: }
182:
183: /**
184: * Request saving of update. If the project is not of current version and the project can be updated, then
185: * the update is done.
186: * @return <code>true</code> if the metadata are of current version or updated.
187: * @throws IOException if error occurs during saving.
188: */
189: public boolean requestUpdate() throws IOException {
190: try {
191: return ProjectManager.mutex().writeAccess(
192: new Mutex.ExceptionAction<Boolean>() {
193: public Boolean run() throws IOException {
194: if (isCurrent()) {
195: return true;
196: }
197: if (!updateProject.canUpdate()) {
198: return false;
199: }
200: updateProject.saveUpdate(null);
201: return true;
202: }
203: });
204:
205: } catch (MutexException ex) {
206: Exception inner = ex.getException();
207: if (inner instanceof IOException) {
208: throw (IOException) inner;
209: }
210: throw (RuntimeException) inner;
211: }
212: }
213:
214: /**
215: * Return <code>true</code> if the project is of current version.
216: * @return <code>true</code> if the project is of current version.
217: */
218: public boolean isCurrent() {
219: return updateProject.isCurrent();
220: }
221:
222: /**
223: * Get the {@link AntProjectHelper} that is proxied.
224: * @return the {@link AntProjectHelper} that is proxied.
225: */
226: public AntProjectHelper getAntProjectHelper() {
227: return helper;
228: }
229: }
|