Author: scabanovich
Date: 2010-09-27 08:04:36 -0400 (Mon, 27 Sep 2010)
New Revision: 25225
Added:
trunk/common/plugins/org.jboss.tools.common.model/src/org/jboss/tools/common/model/filesystems/impl/ThreadSafeCopyFactory.java
Modified:
trunk/common/plugins/org.jboss.tools.common.model/src/org/jboss/tools/common/model/filesystems/impl/AbstractExtendedXMLFileImpl.java
trunk/common/plugins/org.jboss.tools.common.model/src/org/jboss/tools/common/model/filesystems/impl/FolderImpl.java
trunk/common/plugins/org.jboss.tools.common.model/src/org/jboss/tools/common/model/filesystems/impl/JarAccess.java
trunk/common/plugins/org.jboss.tools.common.model/src/org/jboss/tools/common/model/filesystems/impl/JarFolderImpl.java
Log:
JBIDE-7148
https://jira.jboss.org/browse/JBIDE-7148
Modified:
trunk/common/plugins/org.jboss.tools.common.model/src/org/jboss/tools/common/model/filesystems/impl/AbstractExtendedXMLFileImpl.java
===================================================================
---
trunk/common/plugins/org.jboss.tools.common.model/src/org/jboss/tools/common/model/filesystems/impl/AbstractExtendedXMLFileImpl.java 2010-09-27
11:01:11 UTC (rev 25224)
+++
trunk/common/plugins/org.jboss.tools.common.model/src/org/jboss/tools/common/model/filesystems/impl/AbstractExtendedXMLFileImpl.java 2010-09-27
12:04:36 UTC (rev 25225)
@@ -12,7 +12,6 @@
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
-import org.eclipse.swt.widgets.Display;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
@@ -24,7 +23,6 @@
import org.jboss.tools.common.model.filesystems.impl.AbstractXMLFileImpl;
import org.jboss.tools.common.model.loaders.*;
import org.jboss.tools.common.model.markers.ConstraintChecker;
-import org.jboss.tools.common.model.plugin.ModelPlugin;
import org.jboss.tools.common.model.impl.*;
import org.jboss.tools.common.model.util.*;
@@ -35,9 +33,21 @@
public class AbstractExtendedXMLFileImpl extends AbstractXMLFileImpl {
private static final long serialVersionUID = 7942041044569562286L;
ConstraintChecker constraintChecker = new ConstraintChecker(this);
+
+ ThreadSafeCopyFactory threadSafeCopyFactory = null;
public AbstractExtendedXMLFileImpl() {}
+ /**
+ * Returns ready to be loaded copy of this object if and only if this object is being
loaded by another thread.
+ * Otherwise, returns null.
+ *
+ * @return
+ */
+ XModelObject getThreadSafeCopy() {
+ return threadSafeCopyFactory == null ? null :
threadSafeCopyFactory.getThreadSafeCopy();
+ }
+
public boolean hasChildren() {
return true;
}
@@ -52,6 +62,11 @@
if(loadAttributeSeparately(name)) return super.get(name);
loadChildren();
+ XModelObject copy = getThreadSafeCopy();
+ if(copy != null) {
+ return copy.get(name);
+ }
+
}
return super.get(name);
}
@@ -74,7 +89,8 @@
*/
private boolean loadAttributeSeparately(String xmlname) {
BodySource source = getBodySource();
- if(source == null) return true;
+ if(source == null) return threadSafeCopyFactory == null;
+
if(!shouldLoadAttributeSeparately(xmlname)) return false;
if(xmlname == null || xmlname.length() == 0) return false;
String oldvalue = super.get(xmlname);
@@ -95,20 +111,34 @@
public boolean isObjectEditable() {
return super.isObjectEditable() &&
(!XModelObjectConstants.YES.equals(get("_hasErrors_"))); //$NON-NLS-1$
}
+
+ public XModelObject[] getChildren() {
+ XModelObject copy = getThreadSafeCopy();
+ return (copy != null) ? copy.getChildren() : super.getChildren();
+ }
protected void loadChildren() {
+ getThreadSafeCopy();
+
BodySource source = getBodySource();
if (source == null) return;
+
+ threadSafeCopyFactory = new ThreadSafeCopyFactory(this);
+
super.setBodySource(null);
XObjectLoader loader = XModelObjectLoaderUtil.getObjectLoader(this);
String body = source.get();
XModelObjectLoaderUtil.setTempBody(this, body);
loader.load(this);
+
+ threadSafeCopyFactory.destroy();
+ threadSafeCopyFactory = null;
+
if(!isIncorrect() && !isOverlapped()) {
runCheckerOnLoad();
}
}
- WorkspaceJob checkerOnLoad = new WorkspaceJob("Checking on load...") {
+ WorkspaceJob checkerOnLoad = new WorkspaceJob("Checking on load...") {
//$NON-NLS-1$
@Override
public IStatus runInWorkspace(IProgressMonitor monitor)
@@ -166,7 +196,7 @@
String entity = getModel().getEntityRecognizer().getEntityName(new
EntityRecognizerContext(toFileName(this),
getAttributeValue(XModelObjectConstants.ATTR_NAME_EXTENSION), body));
if(entity == null || !entity.equals(getModelEntity().getName())) {
String[] errors = (body.length() == 0) ? null : XMLUtil.getXMLErrors(new
java.io.StringReader(body), false);
- if(errors == null || errors.length == 0) errors = new String[]{"Doctype has been
changed. Please save file for the change to take effect in object model. :0:0"};
+ if(errors == null || errors.length == 0) errors = new String[]{"Doctype has been
changed. Please save file for the change to take effect in object model. :0:0"};
//$NON-NLS-1$
setErrors(body, errors);
XModelImpl m = (XModelImpl)getModel();
m.fireStructureChanged(this);
Modified:
trunk/common/plugins/org.jboss.tools.common.model/src/org/jboss/tools/common/model/filesystems/impl/FolderImpl.java
===================================================================
---
trunk/common/plugins/org.jboss.tools.common.model/src/org/jboss/tools/common/model/filesystems/impl/FolderImpl.java 2010-09-27
11:01:11 UTC (rev 25224)
+++
trunk/common/plugins/org.jboss.tools.common.model/src/org/jboss/tools/common/model/filesystems/impl/FolderImpl.java 2010-09-27
12:04:36 UTC (rev 25225)
@@ -47,6 +47,7 @@
import org.jboss.tools.common.model.filesystems.XFileObject;
import org.jboss.tools.common.model.impl.RegularObjectImpl;
import org.jboss.tools.common.model.impl.XModelImpl;
+import org.jboss.tools.common.model.impl.XModelObjectImpl;
import org.jboss.tools.common.model.loaders.AuxiliaryLoader;
import org.jboss.tools.common.model.loaders.EntityRecognizerContext;
import org.jboss.tools.common.model.loaders.Reloadable;
@@ -220,7 +221,7 @@
}
addChild(c);
} else {
- createFileObject(f);
+ createFileObject(f, true);
}
peer.register(f);
}
@@ -245,18 +246,22 @@
return p;
}
- private void createFileObject(File f) {
- createFileObject(f, getEntityProperties(f));
+ private XModelObject createFileObject(File f, boolean add) {
+ return createFileObject(f, getEntityProperties(f), add);
}
- private void createFileObject(File f, Properties p) {
+ private XModelObject createFileObject(File f, Properties p) {
+ return createFileObject(f, p, true);
+ }
+
+ private XModelObject createFileObject(File f, Properties p, boolean add) {
BodySource bs = getBodySource(f);
String body = p.getProperty(XModelObjectConstants.ATTR_NAME_BODY);
String entity = p.getProperty(XMetaDataConstants.ENTITY);
XModelObject c = getModel().createModelObject(entity, p);
if(c == null) {
ModelPlugin.getPluginLog().logInfo("Cannot create file for entity " +
entity); //$NON-NLS-1$
- return;
+ return null;
}
if(isLateloadFile2(c)) {
((FileAnyImpl)c).setBodySource(bs);
@@ -277,9 +282,25 @@
if(linked.filesByFileName.containsValue(f)) {
c.setObject("file", f); //$NON-NLS-1$
}
- addChild(c);
+ if(add) {
+ addChild(c);
+ } else {
+ ((XModelObjectImpl)c).setParent_0(this);
+ }
+
+ return c;
}
+ public XModelObject createValidChildCopy(XModelObject child) {
+ File pf = getFile();
+ String s = FileAnyImpl.toFileName(child);
+ File f = new File(pf, s);
+ if(f.exists()) {
+ return createFileObject(f, false);
+ }
+ return null;
+ }
+
int updateLock = 0;
Set<String> unsynchronized = null;
public boolean update() {
Modified:
trunk/common/plugins/org.jboss.tools.common.model/src/org/jboss/tools/common/model/filesystems/impl/JarAccess.java
===================================================================
---
trunk/common/plugins/org.jboss.tools.common.model/src/org/jboss/tools/common/model/filesystems/impl/JarAccess.java 2010-09-27
11:01:11 UTC (rev 25224)
+++
trunk/common/plugins/org.jboss.tools.common.model/src/org/jboss/tools/common/model/filesystems/impl/JarAccess.java 2010-09-27
12:04:36 UTC (rev 25225)
@@ -60,11 +60,11 @@
return location;
}
- public boolean isLoaded() {
+ public synchronized boolean isLoaded() {
return (exists || loading);
}
- public void validate() {
+ public synchronized void validate() {
if (isLoaded()) return;
loading = true;
templocation = null;
Modified:
trunk/common/plugins/org.jboss.tools.common.model/src/org/jboss/tools/common/model/filesystems/impl/JarFolderImpl.java
===================================================================
---
trunk/common/plugins/org.jboss.tools.common.model/src/org/jboss/tools/common/model/filesystems/impl/JarFolderImpl.java 2010-09-27
11:01:11 UTC (rev 25224)
+++
trunk/common/plugins/org.jboss.tools.common.model/src/org/jboss/tools/common/model/filesystems/impl/JarFolderImpl.java 2010-09-27
12:04:36 UTC (rev 25225)
@@ -75,7 +75,7 @@
XModelObject c = getModel().createModelObject("JarFolder", p);
//$NON-NLS-1$
addChild(c);
} else {
- createFileObject(jar, path, cs[i]);
+ createFileObject(jar, path, cs[i], true);
}
}
fire = true;
@@ -83,7 +83,7 @@
loaded = true;
}
- private void createFileObject(JarAccess jar, String path, String name) {
+ private XModelObject createFileObject(JarAccess jar, String path, String name,
boolean add) {
String cpath = (path.length() == 0) ? name : path +
XModelObjectConstants.SEPARATOR + name;
Properties p = new Properties();
FolderImpl.parseFileName(p, name);
@@ -110,9 +110,25 @@
loader.load(c);
}
}
- addChild(c);
+ if(add) {
+ addChild(c);
+ } else {
+ ((XModelObjectImpl)c).setParent_0(this);
+ }
+ return c;
}
+ public XModelObject createValidChildCopy(XModelObject child) {
+ JarAccess jar = getJarSystem().getJarAccess();
+ if(!jar.isLoaded()) return null;
+ jar.lockJar();
+ String path = getAbsolutePath();
+ String item = FileAnyImpl.toFileName(child);
+ XModelObject copy = createFileObject(jar, path, item, false);
+ jar.unlockJar();
+ return copy;
+ }
+
protected boolean fire = false;
protected void fireStructureChanged(int kind, Object info) {
Added:
trunk/common/plugins/org.jboss.tools.common.model/src/org/jboss/tools/common/model/filesystems/impl/ThreadSafeCopyFactory.java
===================================================================
---
trunk/common/plugins/org.jboss.tools.common.model/src/org/jboss/tools/common/model/filesystems/impl/ThreadSafeCopyFactory.java
(rev 0)
+++
trunk/common/plugins/org.jboss.tools.common.model/src/org/jboss/tools/common/model/filesystems/impl/ThreadSafeCopyFactory.java 2010-09-27
12:04:36 UTC (rev 25225)
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Red Hat, Inc.
+ * Distributed under license by Red Hat, Inc. All rights reserved.
+ * This program is made available under the terms of the
+ * Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at
http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Red Hat, Inc. - initial API and implementation
+ ******************************************************************************/
+package org.jboss.tools.common.model.filesystems.impl;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.jboss.tools.common.model.XModelObject;
+
+/**
+ * This factory provides a new ready to be loaded copy of delegated model object in case
when
+ * the delegated model object is being loaded by another thread, and there is a danger of
deadlock
+ * in waiting for completion of its loading. If the delegate is loaded, factory returns
null.
+ *
+ * @author Viacheslav Kabanovich
+ *
+ */
+public class ThreadSafeCopyFactory {
+ XModelObject object;
+
+ Thread loadingThread = Thread.currentThread();
+ Map<Thread, XModelObject> concurrentlyLoaded = null;
+
+ public ThreadSafeCopyFactory(XModelObject object) {
+ this.object = object;
+ }
+
+ /**
+ * Returns ready to be loaded copy of model object if and only if
+ * this object is being loaded by another thread.
+ * Otherwise, returns null.
+ *
+ * @return
+ */
+ XModelObject getThreadSafeCopy() {
+ if(loadingThread == null) {
+ concurrentlyLoaded = null;
+ return null;
+ }
+ if(Thread.currentThread() == loadingThread) {
+ return null;
+ }
+
+ Map<Thread, XModelObject> map = concurrentlyLoaded;
+ XModelObject copy = null;
+ if(map != null) {
+ copy = map.get(Thread.currentThread());
+ if(copy != null) return copy;
+ }
+ if(object.getParent() instanceof JarFolderImpl) {
+ copy = ((JarFolderImpl)object.getParent()).createValidChildCopy(object);
+ } else if(object.getParent() instanceof FolderImpl) {
+ copy = ((FolderImpl)object.getParent()).createValidChildCopy(object);
+ }
+ if(copy != null) {
+// System.out.println("Created copy of " + copy.getPath() + " for thread
" + Thread.currentThread() + ". Main object is being loaded by thread " +
loadingThread);
+ //Let us wait a bit for this object, maybe there is no lock.
+ for (int i = 0; i < 50; i++) {
+ Thread t = loadingThread;
+ if (t != null) try {
+ t.join(100);
+ } catch (InterruptedException e) {
+ //ignore
+ }
+ if(loadingThread == null) {
+// System.out.println("Drop copy of " + FileAnyImpl.toFileName(copy) +
" for thread " + Thread.currentThread() + ". Main object is loaded while it
was built in " + (i * 100) + " ms.");
+ return null;
+ }
+ }
+ if(map == null) {
+ map = new HashMap<Thread, XModelObject>();
+ concurrentlyLoaded = map;
+ }
+ map.put(Thread.currentThread(), (AbstractExtendedXMLFileImpl)copy);
+ }
+ return copy;
+ }
+
+ public void destroy() {
+ loadingThread = null;
+ concurrentlyLoaded = null;
+ }
+
+}
Property changes on:
trunk/common/plugins/org.jboss.tools.common.model/src/org/jboss/tools/common/model/filesystems/impl/ThreadSafeCopyFactory.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain