| /* |
| * 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.glassfish.common; |
| |
| import java.io.IOException; |
| import java.util.*; |
| import java.util.logging.Level; |
| import java.util.logging.Logger; |
| import java.util.prefs.BackingStoreException; |
| import javax.swing.event.ChangeListener; |
| import org.netbeans.modules.glassfish.tooling.GlassFishStatus; |
| import org.netbeans.modules.glassfish.tooling.admin.CommandSetProperty; |
| import org.netbeans.modules.glassfish.tooling.server.config.ConfigBuilderProvider; |
| import org.netbeans.api.server.ServerInstance; |
| import org.netbeans.modules.glassfish.common.parser.DomainXMLChangeListener; |
| import org.netbeans.modules.glassfish.common.utils.ServerUtils; |
| import org.netbeans.modules.glassfish.common.utils.Util; |
| import org.netbeans.modules.glassfish.spi.CommandFactory; |
| import org.netbeans.modules.glassfish.spi.GlassfishModule; |
| import org.netbeans.modules.glassfish.spi.RegisteredDDCatalog; |
| import org.netbeans.spi.server.ServerInstanceImplementation; |
| import org.netbeans.spi.server.ServerInstanceProvider; |
| import org.openide.filesystems.FileObject; |
| import org.openide.util.*; |
| import org.openide.util.lookup.Lookups; |
| |
| /** |
| * GlassFish server instances provider. |
| * <p/> |
| * Handles all registered GlassFish server instances. Implemented as singleton |
| * because NetBeans GUI components require singleton implementing |
| * {@link ServerInstanceProvider} interface. |
| * <p/> |
| * @author Peter Williams, Vince Kraemer, Tomas Kraus |
| */ |
| public final class GlassfishInstanceProvider implements ServerInstanceProvider, LookupListener { |
| |
| /** Local logger. */ |
| private static final Logger LOGGER |
| = GlassFishLogger.get(GlassfishInstanceProvider.class); |
| |
| public static final String GLASSFISH_AUTOREGISTERED_INSTANCE = "glassfish_autoregistered_instance"; |
| |
| private static final String AUTOINSTANCECOPIED = "autoinstance-copied"; // NOI18N |
| |
| private volatile static GlassfishInstanceProvider glassFishProvider; |
| |
| public static final String EE6_DEPLOYER_FRAGMENT = "deployer:gfv3ee6"; // NOI18N |
| public static final String EE8_DEPLOYER_FRAGMENT = "deployer:gfv5ee8"; // NOI18N |
| public static final String EE6WC_DEPLOYER_FRAGMENT = "deployer:gfv3ee6wc"; // NOI18N |
| public static final String PRELUDE_DEPLOYER_FRAGMENT = "deployer:gfv3"; // NOI18N |
| static private String EE6_INSTANCES_PATH = "/GlassFishEE6/Instances"; // NOI18N |
| static private String EE8_INSTANCES_PATH = "/GlassFishEE8/Instances"; // NOI18N |
| static private String EE6WC_INSTANCES_PATH = "/GlassFishEE6WC/Instances"; // NOI18N |
| |
| static public String PRELUDE_DEFAULT_NAME = "GlassFish_v3_Prelude"; //NOI18N |
| static public String EE6WC_DEFAULT_NAME = "GlassFish_Server_3.1"; // NOI18N |
| |
| // GlassFish Tooling SDK configuration should be done before any server |
| // instance is created and used. |
| static { |
| GlassFishSettings.toolingLibraryconfig(); |
| } |
| |
| public static GlassfishInstanceProvider getProvider() { |
| if (glassFishProvider != null) { |
| return glassFishProvider; |
| } |
| else { |
| boolean runInit = false; |
| synchronized(GlassfishInstanceProvider.class) { |
| if (glassFishProvider == null) { |
| runInit = true; |
| glassFishProvider = new GlassfishInstanceProvider( |
| new String[]{EE6_DEPLOYER_FRAGMENT, EE6WC_DEPLOYER_FRAGMENT, EE8_DEPLOYER_FRAGMENT}, |
| new String[]{EE6_INSTANCES_PATH, EE6WC_INSTANCES_PATH, EE8_INSTANCES_PATH}, |
| null, |
| true, |
| new String[]{"--nopassword"}, // NOI18N |
| new CommandFactory() { |
| |
| @Override |
| public CommandSetProperty getSetPropertyCommand( |
| String property, String value) { |
| return new CommandSetProperty(property, |
| value, "DEFAULT={0}={1}"); |
| } |
| |
| }); |
| } |
| } |
| if (runInit) { |
| glassFishProvider.init(); |
| } |
| return glassFishProvider; |
| } |
| } |
| |
| public static final Set<String> activeRegistrationSet = Collections.synchronizedSet(new HashSet<String>()); |
| |
| private final Map<String, GlassfishInstance> instanceMap = |
| Collections.synchronizedMap(new HashMap<String, GlassfishInstance>()); |
| private static final Set<String> activeDisplayNames = Collections.synchronizedSet(new HashSet<String>()); |
| private final ChangeSupport support = new ChangeSupport(this); |
| |
| final private String[] instancesDirNames; |
| final private String displayName; |
| final private String[] uriFragments; |
| final private boolean needsJdk6; |
| final private List<String> noPasswordOptions; |
| final private CommandFactory cf; |
| final private Lookup.Result<RegisteredDDCatalog> lookupResult = Lookups.forPath(Util.GF_LOOKUP_PATH).lookupResult(RegisteredDDCatalog.class); |
| |
| @SuppressWarnings("LeakingThisInConstructor") |
| private GlassfishInstanceProvider( |
| String[] uriFragments, |
| String[] instancesDirNames, |
| String displayName, |
| boolean needsJdk6, |
| String[] noPasswordOptionsArray, |
| CommandFactory cf |
| ) { |
| this.instancesDirNames = instancesDirNames; |
| this.displayName = displayName; |
| this.uriFragments = uriFragments; |
| this.needsJdk6 = needsJdk6; |
| this.noPasswordOptions = new ArrayList<>(); |
| if (null != noPasswordOptionsArray) { |
| noPasswordOptions.addAll(Arrays.asList(noPasswordOptionsArray)); |
| } |
| this.cf = cf; |
| lookupResult.allInstances(); |
| |
| lookupResult.addLookupListener(this); |
| } |
| |
| @Override |
| public void resultChanged(LookupEvent ev) { |
| LOGGER.log(Level.FINE, "***** resultChanged fired ******** {0}", hashCode()); // NOI18N |
| RegisteredDDCatalog catalog = getDDCatalog(); |
| if (null != catalog) { |
| catalog.registerEE6RunTimeDDCatalog(this); |
| } |
| refreshCatalogFromFirstInstance(this, getDDCatalog()); |
| } |
| |
| /** |
| * Check providers initialization status. |
| * <p> |
| * @return <code>true</code> when at least one of the providers |
| * is initialized or <code>false</code> otherwise. |
| */ |
| public static synchronized boolean initialized() { |
| return glassFishProvider != null; |
| } |
| |
| private static RegisteredDDCatalog getDDCatalog() { |
| return Lookups.forPath(Util.GF_LOOKUP_PATH).lookup(RegisteredDDCatalog.class); |
| } |
| |
| private static void refreshCatalogFromFirstInstance(GlassfishInstanceProvider gip, RegisteredDDCatalog catalog) { |
| GlassfishInstance firstInstance = gip.getFirstServerInstance(); |
| if (null != firstInstance) { |
| catalog.refreshRunTimeDDCatalog(gip, firstInstance.getGlassfishRoot()); |
| } |
| } |
| |
| /** |
| * Get API representation of GlassFish server instance matching |
| * provided internal server URI. |
| * <p/> |
| * @param uri Internal server URI used as key to find |
| * {@link ServerInstance}. |
| * @return {@link ServerInstance} matching given URI. |
| */ |
| public static ServerInstance getInstanceByUri(String uri) { |
| return getProvider().getInstance(uri); |
| } |
| |
| /** |
| * Get {@link GlassfishInstance} matching provided internal |
| * server URI. |
| * <p/> |
| * @param uri Internal server URI used as key to find |
| * {@link GlassfishInstance}. |
| * @return {@link GlassfishInstance} matching provided internal server URI |
| * or <code>null</code> when no matching object was found. |
| */ |
| public static GlassfishInstance getGlassFishInstanceByUri(String uri) { |
| return getProvider().getGlassfishInstance(uri); |
| } |
| |
| private GlassfishInstance getFirstServerInstance() { |
| if (!instanceMap.isEmpty()) { |
| return instanceMap.values().iterator().next(); |
| } |
| return null; |
| } |
| |
| /** |
| * Retrieve {@link GlassfishInstance} matching provided |
| * internal server URI. |
| * <p/> |
| * @param uri Internal server URI used as key to find |
| * {@link GlassfishInstance}. |
| * @return {@link GlassfishInstance} matching provided internal server URI |
| * or <code>null</code> when no matching object was found. |
| */ |
| public GlassfishInstance getGlassfishInstance(String uri) { |
| synchronized(instanceMap) { |
| return instanceMap.get(uri); |
| } |
| } |
| |
| /** |
| * Add GlassFish server instance into this provider. |
| * <p/> |
| * @param si GlassFish server instance to be added. |
| */ |
| public void addServerInstance(GlassfishInstance si) { |
| synchronized(instanceMap) { |
| try { |
| instanceMap.put(si.getDeployerUri(), si); |
| activeDisplayNames.add(si.getDisplayName()); |
| if (instanceMap.size() == 1) { // only need to do if this first of this type |
| RegisteredDDCatalog catalog = getDDCatalog(); |
| if (null != catalog) { |
| catalog.refreshRunTimeDDCatalog(this, si.getGlassfishRoot()); |
| } |
| } |
| GlassfishInstance.writeInstanceToFile(si); |
| } catch(IOException ex) { |
| LOGGER.log(Level.INFO, |
| "Could not store GlassFish server attributes", ex); |
| } |
| } |
| if (!si.isRemote()) { |
| DomainXMLChangeListener.registerListener(si); |
| } |
| support.fireChange(); |
| } |
| |
| /** |
| * Remove GlassFish server instance from this provider. |
| * <p/> |
| * @param si GlassFish server instance to be removed. |
| */ |
| public boolean removeServerInstance(GlassfishInstance si) { |
| boolean result = false; |
| synchronized(instanceMap) { |
| if(instanceMap.remove(si.getDeployerUri()) != null) { |
| result = true; |
| removeInstanceFromFile(si.getDeployerUri()); |
| activeDisplayNames.remove(si.getDisplayName()); |
| // If this was the last of its type, need to remove the |
| // resolver catalog contents |
| if (instanceMap.isEmpty()) { |
| RegisteredDDCatalog catalog = getDDCatalog(); |
| if (null != catalog) { |
| catalog.refreshRunTimeDDCatalog(this, null); |
| } |
| } |
| } |
| } |
| GlassFishStatus.remove(si); |
| if (result) { |
| ConfigBuilderProvider.destroyBuilder(si); |
| if (!si.isRemote()) { |
| DomainXMLChangeListener.unregisterListener(si); |
| } |
| support.fireChange(); |
| } |
| return result; |
| } |
| |
| public Lookup getLookupFor(ServerInstance instance) { |
| synchronized (instanceMap) { |
| for (GlassfishInstance gfInstance : instanceMap.values()) { |
| if (gfInstance.getCommonInstance().equals(instance)) { |
| return gfInstance.getLookup(); |
| } |
| } |
| return null; |
| } |
| } |
| |
| public ServerInstanceImplementation getInternalInstance(String uri) { |
| return instanceMap.get(uri); |
| } |
| |
| public <T> T getInstanceByCapability(String uri, Class <T> serverFacadeClass) { |
| T result = null; |
| GlassfishInstance instance = instanceMap.get(uri); |
| if(instance != null) { |
| result = instance.getLookup().lookup(serverFacadeClass); |
| } |
| return result; |
| } |
| |
| public <T> List<T> getInstancesByCapability(Class<T> serverFacadeClass) { |
| List<T> result = new ArrayList<>(); |
| synchronized (instanceMap) { |
| for (GlassfishInstance instance : instanceMap.values()) { |
| T serverFacade = instance.getLookup().lookup(serverFacadeClass); |
| if(serverFacade != null) { |
| result.add(serverFacade); |
| } |
| } |
| } |
| return result; |
| } |
| |
| // ------------------------------------------------------------------------ |
| // ServerInstanceProvider interface implementation |
| // ------------------------------------------------------------------------ |
| @Override |
| public List<ServerInstance> getInstances() { |
| List<ServerInstance> result = new ArrayList<>(); |
| synchronized (instanceMap) { |
| for (GlassfishInstance instance : instanceMap.values()) { |
| ServerInstance si = instance.getCommonInstance(); |
| if (null != si) { |
| result.add(si); |
| } else { |
| String message = "invalid commonInstance for " + instance.getDeployerUri(); // NOI18N |
| LOGGER.log(Level.WARNING, message); // NOI18N |
| if (null != instance.getDeployerUri()) |
| instanceMap.remove(instance.getDeployerUri()); |
| } |
| } |
| } |
| return result; |
| } |
| |
| @Override |
| public void addChangeListener(ChangeListener listener) { |
| support.addChangeListener(listener); |
| } |
| |
| @Override |
| public void removeChangeListener(ChangeListener listener) { |
| support.removeChangeListener(listener); |
| } |
| |
| // Additional interesting API's |
| public boolean hasServer(String uri) { |
| return getInstance(uri) != null; |
| } |
| |
| public ServerInstance getInstance(String uri) { |
| ServerInstance rv = null; |
| GlassfishInstance instance = instanceMap.get(uri); |
| if (null != instance) { |
| rv = instance.getCommonInstance(); |
| if (null == rv) { |
| String message = "invalid commonInstance for " + instance.getDeployerUri(); // NOI18N |
| LOGGER.log(Level.WARNING, message); |
| if (null != instance.getDeployerUri()) |
| instanceMap.remove(instance.getDeployerUri()); |
| } |
| } |
| return rv; |
| } |
| |
| String getInstancesDirFirstName() { |
| return instancesDirNames[0]; |
| } |
| |
| // ------------------------------------------------------------------------ |
| // Internal use only. Used by Installer.close() to quickly identify and |
| // shutdown any instances we started during this IDE session. |
| // ------------------------------------------------------------------------ |
| Collection<GlassfishInstance> getInternalInstances() { |
| return instanceMap.values(); |
| } |
| |
| boolean requiresJdk6OrHigher() { |
| return needsJdk6; |
| } |
| |
| private void init() { |
| synchronized (instanceMap) { |
| try { |
| loadServerInstances(); |
| } catch (RuntimeException ex) { |
| LOGGER.log(Level.INFO, null, ex); |
| } |
| RegisteredDDCatalog catalog = getDDCatalog(); |
| if (null != catalog) { |
| catalog.registerEE6RunTimeDDCatalog(this); |
| refreshCatalogFromFirstInstance(this, catalog); |
| } |
| } |
| for (GlassfishInstance gi : instanceMap.values()) { |
| GlassfishInstance.updateModuleSupport(gi); |
| } |
| } |
| |
| // ------------------------------------------------------------------------ |
| // Persistence for server instances. |
| // ------------------------------------------------------------------------ |
| private void loadServerInstances() { |
| List<FileObject> installedInstances = new LinkedList<>(); |
| for (int j = 0; j < instancesDirNames.length; j++) { |
| FileObject dir |
| = ServerUtils.getRepositoryDir(instancesDirNames[j], false); |
| if (dir != null) { |
| FileObject[] instanceFOs = dir.getChildren(); |
| if (instanceFOs != null && instanceFOs.length > 0) { |
| for (int i = 0; i < instanceFOs.length; i++) { |
| try { |
| if (instanceFOs[i].getName().startsWith(GLASSFISH_AUTOREGISTERED_INSTANCE)) { |
| installedInstances.add(instanceFOs[i]); |
| continue; |
| } |
| GlassfishInstance si = GlassfishInstance |
| .readInstanceFromFile(instanceFOs[i], false); |
| if (si != null) { |
| activeDisplayNames.add(si.getDisplayName()); |
| } else { |
| LOGGER.log(Level.FINER, |
| "Unable to create glassfish instance for {0}", // NOI18N |
| instanceFOs[i].getPath()); |
| } |
| } catch (IOException ex) { |
| LOGGER.log(Level.INFO, null, ex); |
| } |
| } |
| } |
| } |
| } |
| if (!installedInstances.isEmpty() |
| && null == NbPreferences.forModule(this.getClass()) |
| .get(AUTOINSTANCECOPIED, null)) { |
| try { |
| for (FileObject installedInstance : installedInstances) { |
| GlassfishInstance igi = GlassfishInstance. |
| readInstanceFromFile(installedInstance, true); |
| activeDisplayNames.add(igi.getDisplayName()); |
| } |
| try { |
| NbPreferences.forModule(this.getClass()) |
| .put(AUTOINSTANCECOPIED, "true"); // NOI18N |
| NbPreferences.forModule(this.getClass()).flush(); |
| } catch (BackingStoreException ex) { |
| LOGGER.log(Level.INFO, |
| "auto-registered instance may reappear", ex); // NOI18N |
| } |
| } catch (IOException ex) { |
| LOGGER.log(Level.INFO, null, ex); |
| } |
| } |
| } |
| |
| private void removeInstanceFromFile(String url) { |
| FileObject instanceFO = getInstanceFileObject(url); |
| if(instanceFO != null && instanceFO.isValid()) { |
| try { |
| instanceFO.delete(); |
| } catch(IOException ex) { |
| LOGGER.log(Level.INFO, null, ex); |
| } |
| } |
| } |
| |
| private FileObject getInstanceFileObject(String url) { |
| for (String instancesDirName : instancesDirNames) { |
| FileObject dir = ServerUtils.getRepositoryDir( |
| instancesDirName, false); |
| if(dir != null) { |
| FileObject[] installedServers = dir.getChildren(); |
| for(int i = 0; i < installedServers.length; i++) { |
| String val = ServerUtils.getStringAttribute( |
| installedServers[i], GlassfishModule.URL_ATTR); |
| if(val != null && val.equals(url) && |
| !installedServers[i].getName().startsWith(GLASSFISH_AUTOREGISTERED_INSTANCE)) { |
| return installedServers[i]; |
| } |
| } |
| } |
| } |
| return null; |
| } |
| |
| String[] getNoPasswordCreatDomainCommand(String startScript, String jarLocation, |
| String domainDir, String portBase, String uname, String domain) { |
| List<String> retVal = new ArrayList<>(); |
| retVal.addAll(Arrays.asList(new String[] {startScript, |
| "-client", // NOI18N |
| "-jar", // NOI18N |
| jarLocation, |
| "create-domain", //NOI18N |
| "--user", //NOI18N |
| uname, |
| "--domaindir", //NOI18N |
| domainDir})); |
| if (null != portBase) { |
| retVal.add("--portbase"); //NOI18N |
| retVal.add(portBase); |
| } |
| if (noPasswordOptions.size() > 0) { |
| retVal.addAll(noPasswordOptions); |
| } |
| retVal.add(domain); |
| return retVal.toArray(new String[retVal.size()]); |
| } |
| |
| public CommandFactory getCommandFactory() { |
| return cf; |
| } |
| |
| } |