| /* |
| * 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.payara.common; |
| |
| import java.io.IOException; |
| import java.util.*; |
| import static java.util.Collections.synchronizedMap; |
| import static java.util.Collections.synchronizedSet; |
| import java.util.logging.Level; |
| import java.util.logging.Logger; |
| import java.util.prefs.BackingStoreException; |
| import javax.swing.event.ChangeListener; |
| import org.netbeans.modules.payara.tooling.PayaraStatus; |
| import org.netbeans.modules.payara.tooling.admin.CommandSetProperty; |
| import org.netbeans.modules.payara.tooling.server.config.ConfigBuilderProvider; |
| import org.netbeans.api.server.ServerInstance; |
| import org.netbeans.modules.payara.common.parser.DomainXMLChangeListener; |
| import org.netbeans.modules.payara.common.utils.ServerUtils; |
| import org.netbeans.modules.payara.common.utils.Util; |
| import org.netbeans.modules.payara.spi.CommandFactory; |
| import org.netbeans.modules.payara.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; |
| import org.netbeans.modules.payara.spi.PayaraModule; |
| |
| /** |
| * Payara server instances provider. |
| * <p/> |
| * Handles all registered Payara 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 PayaraInstanceProvider implements ServerInstanceProvider, LookupListener { |
| |
| /** Local logger. */ |
| private static final Logger LOGGER |
| = PayaraLogger.get(PayaraInstanceProvider.class); |
| |
| public static final String PAYARA_AUTOREGISTERED_INSTANCE = "payara_autoregistered_instance"; |
| |
| private static final String AUTOINSTANCECOPIED = "autoinstance-copied"; // NOI18N |
| |
| private volatile static PayaraInstanceProvider payaraProvider; |
| |
| public static final String EE6_DEPLOYER_FRAGMENT = "deployer:pfv3ee6"; // NOI18N |
| public static final String EE6WC_DEPLOYER_FRAGMENT = "deployer:pfv3ee6wc"; // NOI18N |
| private static final String EE6_INSTANCES_PATH = "/PayaraEE6/Instances"; // NOI18N |
| private static final String EE6WC_INSTANCES_PATH = "/PayaraEE6WC/Instances"; // NOI18N |
| |
| // Payara Tooling SDK configuration should be done before any server |
| // instance is created and used. |
| static { |
| PayaraSettings.toolingLibraryconfig(); |
| } |
| |
| public static PayaraInstanceProvider getProvider() { |
| if (payaraProvider != null) { |
| return payaraProvider; |
| } |
| else { |
| boolean runInit = false; |
| synchronized(PayaraInstanceProvider.class) { |
| if (payaraProvider == null) { |
| runInit = true; |
| payaraProvider = new PayaraInstanceProvider( |
| new String[]{EE6_DEPLOYER_FRAGMENT, EE6WC_DEPLOYER_FRAGMENT}, |
| new String[]{EE6_INSTANCES_PATH, EE6WC_INSTANCES_PATH}, |
| null, |
| true, |
| new String[]{"--nopassword"}, // NOI18N |
| (property, value) -> new CommandSetProperty(property, value, "DEFAULT={0}={1}")); |
| } |
| } |
| if (runInit) { |
| payaraProvider.init(); |
| } |
| return payaraProvider; |
| } |
| } |
| |
| public static final Set<String> activeRegistrationSet |
| = synchronizedSet(new HashSet<>()); |
| |
| private final Map<String, PayaraInstance> instanceMap |
| = synchronizedMap(new HashMap<>()); |
| |
| private static final Set<String> activeDisplayNames |
| = synchronizedSet(new HashSet<>()); |
| |
| 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.PF_LOOKUP_PATH).lookupResult(RegisteredDDCatalog.class); |
| |
| @SuppressWarnings("LeakingThisInConstructor") |
| private PayaraInstanceProvider( |
| 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.registerRunTimeDDCatalog(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 payaraProvider != null; |
| } |
| |
| private static RegisteredDDCatalog getDDCatalog() { |
| return Lookups.forPath(Util.PF_LOOKUP_PATH).lookup(RegisteredDDCatalog.class); |
| } |
| |
| private static void refreshCatalogFromFirstInstance(PayaraInstanceProvider pip, RegisteredDDCatalog catalog) { |
| PayaraInstance firstInstance = pip.getFirstServerInstance(); |
| if (null != firstInstance) { |
| catalog.refreshRunTimeDDCatalog(pip, firstInstance.getPayaraRoot()); |
| } |
| } |
| |
| /** |
| * Get API representation of Payara 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 PayaraInstance} matching provided internal |
| * server URI. |
| * <p/> |
| * @param uri Internal server URI used as key to find |
| * {@link PayaraInstance}. |
| * @return {@link PayaraInstance} matching provided internal server URI |
| * or <code>null</code> when no matching object was found. |
| */ |
| public static PayaraInstance getPayaraInstanceByUri(String uri) { |
| return getProvider().getPayaraInstance(uri); |
| } |
| |
| private PayaraInstance getFirstServerInstance() { |
| if (!instanceMap.isEmpty()) { |
| return instanceMap.values().iterator().next(); |
| } |
| return null; |
| } |
| |
| /** |
| * Retrieve {@link PayaraInstance} matching provided |
| * internal server URI. |
| * <p/> |
| * @param uri Internal server URI used as key to find |
| * {@link PayaraInstance}. |
| * @return {@link PayaraInstance} matching provided internal server URI |
| * or <code>null</code> when no matching object was found. |
| */ |
| public PayaraInstance getPayaraInstance(String uri) { |
| synchronized(instanceMap) { |
| return instanceMap.get(uri); |
| } |
| } |
| |
| /** |
| * Add Payara server instance into this provider. |
| * <p/> |
| * @param si Payara server instance to be added. |
| */ |
| public void addServerInstance(PayaraInstance 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.getPayaraRoot()); |
| } |
| } |
| PayaraInstance.writeInstanceToFile(si); |
| } catch(IOException ex) { |
| LOGGER.log(Level.INFO, |
| "Could not store Payara server attributes", ex); |
| } |
| } |
| if (!si.isRemote()) { |
| DomainXMLChangeListener.registerListener(si); |
| } |
| support.fireChange(); |
| } |
| |
| /** |
| * Remove Payara server instance from this provider. |
| * <p/> |
| * @param si Payara server instance to be removed. |
| */ |
| public boolean removeServerInstance(PayaraInstance 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); |
| } |
| } |
| } |
| } |
| PayaraStatus.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 (PayaraInstance 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; |
| PayaraInstance 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 (PayaraInstance 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 (PayaraInstance 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; |
| PayaraInstance 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<PayaraInstance> 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.registerRunTimeDDCatalog(this); |
| refreshCatalogFromFirstInstance(this, catalog); |
| } |
| } |
| for (PayaraInstance gi : instanceMap.values()) { |
| PayaraInstance.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(PAYARA_AUTOREGISTERED_INSTANCE)) { |
| installedInstances.add(instanceFOs[i]); |
| continue; |
| } |
| PayaraInstance si = PayaraInstance |
| .readInstanceFromFile(instanceFOs[i], false); |
| if (si != null) { |
| activeDisplayNames.add(si.getDisplayName()); |
| } else { |
| LOGGER.log(Level.FINER, |
| "Unable to create payara 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) { |
| PayaraInstance igi = PayaraInstance. |
| 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], PayaraModule.URL_ATTR); |
| if(val != null && val.equals(url) && |
| !installedServers[i].getName().startsWith(PAYARA_AUTOREGISTERED_INSTANCE)) { |
| return installedServers[i]; |
| } |
| } |
| } |
| } |
| return null; |
| } |
| |
| List<String> getNoPasswordOptions() { |
| return noPasswordOptions; |
| } |
| |
| public CommandFactory getCommandFactory() { |
| return cf; |
| } |
| |
| } |