Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.netbeans.modules.ide.ergonomics.fod.FeatureProjectFactory Maven / Gradle / Ivy
/*
* 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.ide.ergonomics.fod;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.IOException;
import java.io.InputStream;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.Icon;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.xml.parsers.DocumentBuilder;
import org.netbeans.api.autoupdate.UpdateElement;
import org.netbeans.api.progress.ProgressHandle;
import org.netbeans.api.project.Project;
import org.netbeans.api.project.ProjectInformation;
import org.netbeans.api.project.ProjectManager;
import org.netbeans.spi.project.ProjectFactory;
import org.netbeans.spi.project.ProjectState;
import org.netbeans.spi.project.SubprojectProvider;
import org.netbeans.spi.project.support.LookupProviderSupport;
import org.netbeans.spi.project.ui.ProjectOpenedHook;
import org.netbeans.spi.project.ui.support.UILookupMergerSupport;
import org.openide.filesystems.FileObject;
import org.openide.nodes.Node;
import org.openide.util.Exceptions;
import org.openide.util.ImageUtilities;
import org.openide.util.Lookup;
import org.openide.util.RequestProcessor;
import org.openide.util.WeakListeners;
import org.openide.util.lookup.AbstractLookup;
import org.openide.util.lookup.InstanceContent;
import org.openide.util.lookup.Lookups;
import org.openide.util.lookup.ProxyLookup;
import org.openide.util.lookup.ServiceProvider;
import org.w3c.dom.Document;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.netbeans.api.project.ui.OpenProjects;
import org.netbeans.spi.project.ui.LogicalViewProvider;
import org.openide.filesystems.FileUtil;
import org.openide.loaders.DataFolder;
import org.openide.nodes.FilterNode;
import org.openide.util.NbBundle;
import org.openide.util.RequestProcessor.Task;
import org.xml.sax.SAXException;
/**
*
* @author Jaroslav Tulach , Jirka Rechtacek
*/
@ServiceProvider(service=ProjectFactory.class, position=30000)
public class FeatureProjectFactory
implements ProjectFactory, PropertyChangeListener, Runnable {
static final Logger LOG = Logger.getLogger("org.netbeans.modules.ide.ergonomics.projects"); // NOI18N
public FeatureProjectFactory() {
OpenProjects.getDefault().addPropertyChangeListener(this);
}
static Icon loadIcon() {
return ImageUtilities.loadImageIcon(
"org/netbeans/modules/ide/ergonomics/fod/project.png" // NOI18N
, false
);
}
static final class Data {
private final boolean deepCheck;
private final FileObject dir;
private Map data;
private Map doms;
public Data(FileObject dir, boolean deepCheck) {
this.deepCheck = deepCheck;
this.dir = dir;
}
Document dom(String relative) {
Document doc = doms == null ? null : doms.get(relative);
if (doc != null) {
return doc;
}
FileObject fo = dir.getFileObject(relative);
if (fo == null) {
return null;
}
File f = FileUtil.toFile(fo);
try {
DocumentBuilder b = DocumentBuilderFactory.newInstance().newDocumentBuilder();
if (f != null) {
doc = b.parse(f);
} else {
InputStream is = fo.getInputStream();
doc = b.parse(is);
}
if (doms == null) {
doms = new HashMap();
}
doms.put(relative, doc);
return doc;
} catch (ParserConfigurationException parserConfigurationException) {
LOG.log(Level.WARNING, "Cannot configure XML parser", parserConfigurationException); // NOI18N
} catch (SAXException sAXException) {
LOG.log(Level.INFO, "XML broken in " + f, sAXException); // NOI18N
} catch (Exception any) {
LOG.log(Level.INFO, "Cannot read " + f, any); // NOI18N
}
return null;
}
final boolean hasFile(String relative) {
FileObject d = dir;
int pos = 0;
while (relative.startsWith("../", pos) && d != null) {
d = d.getParent();
pos += 3;
}
if (d == null) {
return false;
}
relative = relative.substring(pos);
if (relative.contains("*")) {
for (String segment : relative.split("/")) {
FOUND: if (segment.contains("*")) {
assert segment.endsWith("*");
String prefix = segment.substring(0, segment.length() - 1);
for (FileObject ch : d.getChildren()) {
if (ch.getNameExt().startsWith(prefix)) {
d = ch;
break FOUND;
}
}
return false;
} else {
d = d.getFileObject(segment);
}
if (d == null) {
return false;
}
}
return true;
}
return d.getFileObject(relative) != null;
}
final boolean isDeepCheck() {
return deepCheck;
}
@Override
public String toString() {
return dir.getPath();
}
final synchronized String is(String relative) {
FileObject prj = dir.getFileObject(relative);
if (prj == null) {
return null;
}
String content = data == null ? null : data.get(relative);
if (content != null) {
return content;
}
byte[] arr = new byte[4000];
int len;
InputStream is = null;
try {
is = prj.getInputStream();
len = is.read(arr);
if (len >= 0) {
content = new String(arr, 0, len, StandardCharsets.UTF_8);
}
} catch (IOException ex) {
LOG.log(Level.FINEST, "exception while reading " + prj, ex); // NOI18N
len = -1;
} finally {
if (is != null) {
try {
is.close();
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
}
}
}
LOG.log(Level.FINEST, " read {0} bytes", len); // NOI18N
if (len == -1) {
return null;
}
if (data == null) {
data = new HashMap();
}
data.put(relative, content);
return content;
}
}
public boolean isProject(FileObject projectDirectory) {
Data d = new Data(projectDirectory, false);
for (FeatureInfo info : FeatureManager.features()) {
if (!info.isPresent()) {
continue;
}
if (!info.isEnabled() && (info.isProject(d) == 1)) {
return true;
}
}
return false;
}
public Project loadProject(FileObject projectDirectory, ProjectState state) throws IOException {
Data d = new Data(projectDirectory, true);
FeatureInfo lead = null;
List additional = new ArrayList();
int notEnabled = 0;
for (FeatureInfo info : FeatureManager.features()) {
if (!info.isPresent()) {
continue;
}
switch (info.isProject(d)) {
case 0: break;
case 1:
lead = info;
if (!info.isEnabled()) {
notEnabled++;
}
break;
case 2:
additional.add(info);
if (!info.isEnabled()) {
notEnabled++;
}
break;
default: assert false;
}
}
if (lead == null || notEnabled == 0) {
return null;
}
return new FeatureNonProject(projectDirectory, lead, state, additional);
}
@Override
public void saveProject(Project project) throws IOException, ClassCastException {
}
@Override
public void run() {
final Project[] toCheck = OpenProjects.getDefault().getOpenProjects();
checkProjects(toCheck);
}
private void checkProjects(final Project[] toCheck) {
final List additional = new ArrayList();
FeatureInfo f = null;
for (Project p : toCheck) {
Data d = new Data(p.getProjectDirectory(), true);
for (FeatureInfo info : FeatureManager.features()) {
switch (info.isProject(d)) {
case 0:
break;
case 1:
f = info;
break;
case 2:
f = info;
additional.add(info);
break;
default:
assert false;
}
}
}
if (f != null && !additional.isEmpty()) {
final FeatureInfo finalF = f;
final FeatureInfo[] addF = additional.toArray(new FeatureInfo[0]);
FeatureManager.logUI("ERGO_PROJECT_OPEN", finalF.clusterName);
FindComponentModules findModules = new FindComponentModules(finalF, addF);
Collection toEnable = findModules.getModulesForEnable();
if (toEnable != null && !toEnable.isEmpty()) {
ModulesActivator enabler = new ModulesActivator(toEnable, findModules);
enabler.getEnableTask().waitFinished();
}
}
}
@Override
public void propertyChange(PropertyChangeEvent evt) {
if ("willOpenProjects".equals(evt.getPropertyName())) { // NOI18N
final Object arr = evt.getNewValue();
if (arr instanceof Project[]) {
Task t = FeatureManager.getInstance().create(new Runnable() {
@Override
public void run() {
checkProjects((Project[])arr);
}
});
t.schedule(0);
t.waitFinished();
}
}
if (OpenProjects.PROPERTY_OPEN_PROJECTS.equals(evt.getPropertyName())) {
RequestProcessor.Task t = FeatureManager.getInstance().create(this);
t.schedule(0);
}
}
private static final class FeatureNonProject
implements Project, ChangeListener {
private final FeatureDelegate delegate;
private final FeatureInfo info;
private final FeatureInfo[] additional;
private final Lookup lookup;
private ProjectState state;
private volatile String error;
private final ChangeListener weakL;
public FeatureNonProject(
FileObject dir, FeatureInfo info,
ProjectState state, List additional
) {
this.delegate = new FeatureDelegate(dir, this);
this.info = info;
this.additional = additional.toArray(new FeatureInfo[0]);
this.lookup = Lookups.proxy(delegate);
this.state = state;
this.weakL = WeakListeners.change(this, FeatureManager.getInstance());
FeatureManager.getInstance().addChangeListener(weakL);
}
public FileObject getProjectDirectory() {
return delegate.dir;
}
public Lookup getLookup() {
return lookup;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Project) {
return ((Project)obj).getProjectDirectory().equals(getProjectDirectory());
}
return false;
}
@Override
public int hashCode() {
return getProjectDirectory().hashCode();
}
public void stateChanged(ChangeEvent e) {
if (info.isEnabled()) {
switchToReal();
}
}
final void switchToReal() {
ProjectState s = null;
synchronized (this) {
s = state;
state = null;
}
if (s != null) {
try {
s.notifyDeleted();
Project p = ProjectManager.getDefault().findProject(getProjectDirectory());
if (p == FeatureNonProject.this) {
throw new IllegalStateException("New project shall be found! " + p); // NOI18N
}
delegate.associate(p);
} catch (IOException ex) {
error = ex.getLocalizedMessage();
} catch (Exception ex) {
Exceptions.printStackTrace(ex);
}
}
}
private final class FeatureOpenHook extends ProjectOpenedHook
implements Runnable, ProgressMonitor {
/**
* The finder instance; valid only for the duration of the task,
* should be cleared after that.
*/
private FindComponentModules finder;
@Override
protected void projectOpened() {
if (state == null) {
return;
}
RequestProcessor.Task t = FeatureManager.getInstance().create(this);
t.schedule(0);
t.waitFinished ();
if (error == null) {
switchToReal();
// make sure support for projects we depend on are also enabled
SubprojectProvider sp = getLookup().lookup(SubprojectProvider.class);
if (sp != null) {
for (Project subP : sp.getSubprojects()) {
FeatureNonProject toOpen;
toOpen = subP.getLookup().lookup(FeatureNonProject.class);
if (toOpen != null) {
toOpen.delegate.hook.projectOpened();
}
}
}
} else {
delegate.associate(new BrokenProject(getProjectDirectory(), error));
}
}
@Override
protected void projectClosed() {
}
public void run() {
FeatureManager.logUI("ERGO_PROJECT_OPEN", info.clusterName);
error = null;
FindComponentModules findModules = new FindComponentModules(info, additional);
synchronized (this) {
this.finder = findModules;
}
try {
Collection toInstall = findModules.getModulesForInstall ();
Collection toEnable = findModules.getModulesForEnable ();
if (!findModules.getIncompleteFeatures().isEmpty() && findModules.isDownloadRequired()) {
// ignore
Collection missingModules = new LinkedHashSet<>(findModules.getMissingModules(info));
for (FeatureInfo i2 : additional) {
missingModules.addAll(findModules.getMissingModules(i2));
}
StringBuilder sb = new StringBuilder();
if (!missingModules.isEmpty()) {
for (FeatureInfo.ExtraModuleInfo s : missingModules) {
if (sb.length() > 0) {
sb.append(", "); // NOI18N
}
sb.append(s.displayName());
}
}
error = NbBundle.getMessage(FeatureProjectFactory.class,
"MSG_BrokenAction_FeatureIncomplete",
findModules.getIncompleteFeatures().iterator().next(),
sb.toString());
return;
}
if (toInstall != null && ! toInstall.isEmpty ()) {
ModulesInstaller installer = new ModulesInstaller(toInstall, findModules, this);
installer.getInstallTask ().waitFinished ();
}
if (toEnable != null && ! toEnable.isEmpty () && error == null) {
ModulesActivator enabler = new ModulesActivator (toEnable, findModules, this);
enabler.getEnableTask ().waitFinished ();
}
} finally {
synchronized (this) {
this.finder = null;
}
}
}
public void onDownload(ProgressHandle progressHandle) {
}
public void onValidate(ProgressHandle progressHandle) {
}
public void onInstall(ProgressHandle progressHandle) {
}
public void onEnable(ProgressHandle progressHandle) {
}
public void onError(String message) {
synchronized (this) {
if (finder.isDownloadRequired()) {
error = message;
}
}
}
} // end of FeatureOpenHook
} // end of FeatureNonProject
private static final class FeatureDelegate
implements Lookup.Provider, ProjectInformation, LogicalViewProvider {
private final FileObject dir;
private final PropertyChangeSupport support;
Lookup delegate;
private final InstanceContent ic = new InstanceContent();
private final Lookup hooks = new AbstractLookup(ic);
private final FeatureNonProject.FeatureOpenHook hook;
private List lvs;
public FeatureDelegate(FileObject dir, FeatureNonProject feature) {
this.dir = dir;
this.hook = feature.new FeatureOpenHook();
ic.add(UILookupMergerSupport.createProjectOpenHookMerger(hook));
this.delegate = new ProxyLookup(
Lookups.fixed(feature, this),
LookupProviderSupport.createCompositeLookup(
hooks, "../nonsence" // NOI18N
)
);
this.support = new PropertyChangeSupport(this);
}
public Lookup getLookup() {
return delegate;
}
@Override
public String getName() {
ProjectInformation info = delegate.lookup(ProjectInformation.class);
if (info != null && info != this) {
return info.getName();
}
return dir.getNameExt();
}
@Override
public String getDisplayName() {
ProjectInformation info = delegate.lookup(ProjectInformation.class);
if (info != null && info != this) {
return info.getDisplayName();
}
return getName();
}
@Override
public Icon getIcon() {
ProjectInformation info = delegate.lookup(ProjectInformation.class);
if (info != null && info != this) {
return info.getIcon();
}
return loadIcon();
}
@Override
public Project getProject() {
return delegate.lookup(Project.class);
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
support.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
support.removePropertyChangeListener(listener);
}
final void associate(Project p) {
if (p == null) {
delegate = Lookup.EMPTY;
return;
}
assert dir.equals(p.getProjectDirectory());
ProjectInformation info = p.getLookup().lookup(ProjectInformation.class);
if (info != null) {
for (PropertyChangeListener l : support.getPropertyChangeListeners()) {
info.addPropertyChangeListener(l);
}
}
delegate = p.getLookup();
for (ProjectOpenedHook h : p.getLookup().lookupAll(ProjectOpenedHook.class)) {
ic.add(h);
}
List list = lvs;
lvs = Collections.emptyList();
if (list != null) {
for (RootNode fn : list) {
fn.change(delegate);
}
}
support.firePropertyChange(null, null, null);
}
public Node createLogicalView() {
LogicalViewProvider lvp = delegate.lookup(LogicalViewProvider.class);
if (lvp != null && lvp != this) {
return lvp.createLogicalView();
}
if (lvs == null) {
lvs = new ArrayList();
}
RootNode fn = new RootNode(dir);
lvs.add(fn);
return fn;
}
public Node findPath(Node root, Object target) {
LogicalViewProvider lvp = delegate.lookup(LogicalViewProvider.class);
if (lvp != null && lvp != this) {
return lvp.findPath(root, target);
}
return null;
}
}
private static final class RootNode extends FilterNode {
public RootNode(FileObject fo) {
super(DataFolder.findFolder(fo).getNodeDelegate());
}
public void change(Lookup l) {
LogicalViewProvider lvp = l.lookup(LogicalViewProvider.class);
if (lvp != null) {
changeOriginal(lvp.createLogicalView(), true);
}
}
}
}