/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common
* Development and Distribution License("CDDL") (collectively, the
* "License"). You may not use this file except in compliance with the
* License. You can obtain a copy of the License at
* http://www.netbeans.org/cddl-gplv2.html
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
* specific language governing permissions and limitations under the
* License. When distributing the software, include this License Header
* Notice in each file and include the License file at
* nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the GPL Version 2 section of the License file that
* accompanied this code. If applicable, add the following below the
* License Header, with the fields enclosed by brackets [] replaced by
* your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*
* If you wish your version of this file to be governed by only the CDDL
* or only the GPL Version 2, indicate your decision by adding
* "[Contributor] elects to include this software in this distribution
* under the [CDDL or GPL Version 2] license." If you do not indicate a
* single choice of license, a recipient has the option to distribute
* your version of this file under either the CDDL, the GPL Version 2 or
* to extend the choice of license to its licensees as provided above.
* However, if you add GPL Version 2 code and therefore, elected the GPL
* Version 2 license, then the option applies only if the new code is
* made subject to such option by the copyright holder.
*
* Contributor(s):
*
* Portions Copyrighted 2008 Sun Microsystems, Inc.
*/
package org.netbeans.modules.scala.project;
import java.io.IOException;
import javax.swing.JButton;
import org.netbeans.api.project.Project;
import org.netbeans.api.project.ProjectManager;
import org.netbeans.modules.java.api.common.ant.UpdateImplementation;
import org.netbeans.modules.scala.project.ui.customizer.J2SEProjectProperties;
import org.netbeans.spi.project.AuxiliaryConfiguration;
import org.netbeans.spi.project.support.ant.AntProjectHelper;
import org.netbeans.spi.project.support.ant.EditableProperties;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
import org.openide.util.Mutex;
import org.openide.util.NbBundle;
import org.w3c.dom.Comment;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
/**
*
* @author Tomas Mysik
*/
public class UpdateProjectImpl implements UpdateImplementation {
private static final boolean TRANSPARENT_UPDATE = Boolean.getBoolean("j2seproject.transparentUpdate");
private static final String BUILD_NUMBER = System.getProperty("netbeans.buildnumber"); // NOI18N
private static final String MINIMUM_ANT_VERSION_ELEMENT = "minimum-ant-version";
private final Project project;
private final AntProjectHelper helper;
private final AuxiliaryConfiguration cfg;
private boolean alreadyAskedInWriteAccess;
private Boolean isCurrent;
private Element cachedElement;
/**
* Creates new UpdateHelper
* @param project
* @param helper AntProjectHelper
* @param cfg AuxiliaryConfiguration
* @param genFileHelper GeneratedFilesHelper
* @param notifier used to ask user about project update
*/
UpdateProjectImpl(Project project, AntProjectHelper helper, AuxiliaryConfiguration cfg) {
assert project != null && helper != null && cfg != null;
this.project = project;
this.helper = helper;
this.cfg = cfg;
}
/**
* Returns true if the project is of current version.
* @return true if the project is of current version, otherwise false.
*/
public boolean isCurrent () {
return ProjectManager.mutex().readAccess(new Mutex.Action<Boolean>() {
public Boolean run() {
synchronized (this) {
if (isCurrent == null) {
if ((cfg.getConfigurationFragment("data","http://www.netbeans.org/ns/scala-project/0.1",true) != null) ||
(cfg.getConfigurationFragment("data","http://www.netbeans.org/ns/scala-project/0.2",true) != null)) {
isCurrent = Boolean.FALSE;
} else {
isCurrent = Boolean.TRUE;
}
}
return isCurrent;
}
}
}).booleanValue();
}
public boolean canUpdate () {
if (TRANSPARENT_UPDATE) {
return true;
}
//Ask just once under a single write access
if (alreadyAskedInWriteAccess) {
return false;
}
else {
boolean canUpdate = showUpdateDialog();
if (!canUpdate) {
alreadyAskedInWriteAccess = true;
ProjectManager.mutex().postReadRequest(new Runnable() {
public void run() {
alreadyAskedInWriteAccess = false;
}
});
}
return canUpdate;
}
}
public void saveUpdate(final EditableProperties props) throws IOException {
this.helper.putPrimaryConfigurationData(getUpdatedSharedConfigurationData(),true);
this.cfg.removeConfigurationFragment("data","http://www.netbeans.org/ns/scala-project/0.1",true); //NOI18N
this.cfg.removeConfigurationFragment("data","http://www.netbeans.org/ns/scala-project/0.2",true); //NOI18N
ProjectManager.getDefault().saveProject (this.project);
synchronized(this) {
this.isCurrent = Boolean.TRUE;
}
}
public synchronized Element getUpdatedSharedConfigurationData () {
if (cachedElement == null) {
Element oldRoot = this.cfg.getConfigurationFragment("data","http://www.netbeans.org/ns/scala-project/0.1",true); //NOI18N
if (oldRoot != null) {
Document doc = oldRoot.getOwnerDocument();
Element newRoot = doc.createElementNS (J2SEProjectType.PROJECT_CONFIGURATION_NAMESPACE,"data"); //NOI18N
copyDocument (doc, oldRoot, newRoot);
Element sourceRoots = doc.createElementNS(J2SEProjectType.PROJECT_CONFIGURATION_NAMESPACE,"source-roots"); //NOI18N
Element root = doc.createElementNS (J2SEProjectType.PROJECT_CONFIGURATION_NAMESPACE,"root"); //NOI18N
root.setAttribute ("id","src.dir"); //NOI18N
sourceRoots.appendChild(root);
newRoot.appendChild (sourceRoots);
Element testRoots = doc.createElementNS(J2SEProjectType.PROJECT_CONFIGURATION_NAMESPACE,"test-roots"); //NOI18N
root = doc.createElementNS (J2SEProjectType.PROJECT_CONFIGURATION_NAMESPACE,"root"); //NOI18N
root.setAttribute ("id","test.src.dir"); //NOI18N
testRoots.appendChild (root);
newRoot.appendChild (testRoots);
cachedElement = updateMinAntVersion (newRoot, doc);
} else {
oldRoot = this.cfg.getConfigurationFragment("data","http://www.netbeans.org/ns/scala-project/0.2",true); //NOI18N
if (oldRoot != null) {
Document doc = oldRoot.getOwnerDocument();
Element newRoot = doc.createElementNS (J2SEProjectType.PROJECT_CONFIGURATION_NAMESPACE,"data"); //NOI18N
copyDocument (doc, oldRoot, newRoot);
cachedElement = updateMinAntVersion (newRoot, doc);
}
}
}
return cachedElement;
}
public synchronized EditableProperties getUpdatedProjectProperties () {
EditableProperties cachedProperties = this.helper.getProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH);
//The javadoc.additionalparam was not in NB 4.0
if (cachedProperties.get (J2SEProjectProperties.JAVADOC_ADDITIONALPARAM)==null) {
cachedProperties.put (J2SEProjectProperties.JAVADOC_ADDITIONALPARAM,""); //NOI18N
}
if (cachedProperties.get ("build.generated.dir")==null) { //NOI18N
cachedProperties.put ("build.generated.dir","${build.dir}/generated"); //NOI18N
}
if (cachedProperties.get ("meta.inf.dir")==null) { //NOI18N
cachedProperties.put ("meta.inf.dir","${src.dir}/META-INF"); //NOI18N
}
return cachedProperties;
}
private static void copyDocument (Document doc, Element from, Element to) {
NodeList nl = from.getChildNodes();
int length = nl.getLength();
for (int i=0; i< length; i++) {
Node node = nl.item (i);
Node newNode = null;
switch (node.getNodeType()) {
case Node.ELEMENT_NODE:
Element oldElement = (Element) node;
newNode = doc.createElementNS(J2SEProjectType.PROJECT_CONFIGURATION_NAMESPACE,oldElement.getTagName());
NamedNodeMap m = oldElement.getAttributes();
Element newElement = (Element) newNode;
for (int index = 0; index < m.getLength(); index++) {
Node attr = m.item(index);
newElement.setAttribute(attr.getNodeName(), attr.getNodeValue());
}
copyDocument(doc,oldElement,newElement);
break;
case Node.TEXT_NODE:
Text oldText = (Text) node;
newNode = doc.createTextNode(oldText.getData());
break;
case Node.COMMENT_NODE:
Comment oldComment = (Comment) node;
newNode = doc.createComment(oldComment.getData());
break;
}
if (newNode != null) {
to.appendChild (newNode);
}
}
}
private static Element updateMinAntVersion (final Element root, final Document doc) {
NodeList list = root.getElementsByTagNameNS (J2SEProjectType.PROJECT_CONFIGURATION_NAMESPACE,MINIMUM_ANT_VERSION_ELEMENT);
if (list.getLength() == 1) {
Element me = (Element) list.item(0);
list = me.getChildNodes();
if (list.getLength() == 1) {
me.replaceChild (doc.createTextNode(J2SEProjectGenerator.MINIMUM_ANT_VERSION), list.item(0));
return root;
}
}
assert false : "Invalid project file"; //NOI18N
return root;
}
private boolean showUpdateDialog() {
JButton updateOption = new JButton (NbBundle.getMessage(UpdateProjectImpl.class, "CTL_UpdateOption"));
updateOption.getAccessibleContext().setAccessibleDescription(NbBundle.getMessage(UpdateProjectImpl.class, "AD_UpdateOption"));
return DialogDisplayer.getDefault().notify(
new NotifyDescriptor (NbBundle.getMessage(UpdateProjectImpl.class,"TXT_ProjectUpdate", BUILD_NUMBER),
NbBundle.getMessage(UpdateProjectImpl.class,"TXT_ProjectUpdateTitle"),
NotifyDescriptor.DEFAULT_OPTION,
NotifyDescriptor.WARNING_MESSAGE,
new Object[] {
updateOption,
NotifyDescriptor.CANCEL_OPTION
},
updateOption)) == updateOption;
}
}