/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved. * * Oracle and Java are registered trademarks of Oracle and/or its affiliates. * Other names may be trademarks of their respective owners. * * 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle 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.ruby.railsprojects.server; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyVetoException; import java.beans.VetoableChangeListener; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.netbeans.api.ruby.platform.RubyPlatform; import org.netbeans.api.ruby.platform.RubyPlatformManager; import org.netbeans.modules.ruby.platform.gems.GemInfo; import org.netbeans.modules.ruby.platform.gems.GemManager; import org.netbeans.modules.ruby.railsprojects.server.spi.RubyInstance; import org.netbeans.modules.ruby.railsprojects.server.spi.RubyInstanceProvider; import org.openide.util.lookup.Lookups; /** * A server registry for servers with Ruby capabilities. * * TODO: a work in progess. Need to be better integrated with RubyInstanceProvider, * possibly implement an instance provider for WEBrick/Mongrel instead of * handling them here. * * @author peterw99, Erno Mononen, Michal Papis */ public class ServerRegistry implements VetoableChangeListener { private static ServerRegistry defaultRegistry; /** * Switch for enabling support for Phusion Passenger. */ private static boolean ENABLE_PASSENGER = Boolean.getBoolean("passenger.support"); //NOI18N private ServerRegistry() { } public synchronized static ServerRegistry getDefault() { if (defaultRegistry == null) { defaultRegistry = new ServerRegistry(); RubyPlatformManager.addVetoableChangeListener(defaultRegistry); } return defaultRegistry; } public List<RubyInstance> getServers() { List<RubyInstance> result = new ArrayList<RubyInstance>(); // makes GF the default server for (RubyInstanceProvider provider : Lookups.forPath("Servers/Ruby").lookupAll(RubyInstanceProvider.class)) { result.addAll(provider.getInstances()); } result.addAll(getRubyServers()); return result; } List<RubyInstance> getServers(RubyPlatform platform) { List<RubyInstance> result = new ArrayList<RubyInstance>(); for (RubyInstance each : getServers()) { if (each.isPlatformSupported(platform)) { result.add(each); } } return result; } List<RubyServer> getRubyServers() { List<RubyServer> result = new ArrayList<RubyServer>(); for (RubyPlatform each : RubyPlatformManager.getPlatforms()) { result.addAll(RubyServerFactory.getInstance(each).getServers()); } return result; } public RubyInstance getServer(String serverId, RubyPlatform platform) { for (RubyInstanceProvider provider : Lookups.forPath("Servers/Ruby").lookupAll(RubyInstanceProvider.class)) { RubyInstance instance = provider.getInstance(serverId); if (instance != null && instance.isPlatformSupported(platform)) { return instance; } } for (RubyServer each : RubyServerFactory.getInstance(platform).getServers()) { if (each.getServerUri().equals(serverId) && each.isPlatformSupported(platform)) { return each; } } return null; } public void vetoableChange(PropertyChangeEvent evt) throws PropertyVetoException { if (evt.getPropertyName().equals("platforms")) { //NOI18N ServerInstanceProviderImpl.getInstance().fireServersChanged(); } } /** * A factory for Mongrel and WEBrick instances for a Ruby platform. Takes care * of caching the instances and reinitializing * the server list when there are changes in the gems of the platform. */ private static class RubyServerFactory implements PropertyChangeListener { private static final Map<RubyPlatform, RubyServerFactory> instances = new HashMap<RubyPlatform, ServerRegistry.RubyServerFactory>(); private final RubyPlatform platform; private final List<RubyServer> servers = new ArrayList<RubyServer>(); private RubyServerFactory(RubyPlatform platform) { this.platform = platform; } public static synchronized RubyServerFactory getInstance(RubyPlatform platform) { RubyServerFactory existing = instances.get(platform); if (existing != null) { return existing; } RubyServerFactory result = new RubyServerFactory(platform); result.initGlassFish(); result.initTrinidad(); result.initMongrel(); result.initWEBrick(); if (ENABLE_PASSENGER) { result.initPassenger(); } platform.addPropertyChangeListener(result); instances.put(platform, result); return result; } public List<RubyServer> getServers() { Collections.sort(servers, new ServerComparator()); return Collections.<RubyServer>unmodifiableList(servers); } private RubyServer createInstance(Class clazz, GemInfo gemInfo) { if (clazz == Trinidad.class) { return new Trinidad(platform, gemInfo); } else if (clazz == GlassFishGem.class) { return new GlassFishGem(platform, gemInfo); } else if (clazz == Mongrel.class) { return new Mongrel(platform, gemInfo.getVersion()); } else if (clazz == Passenger.class) { return new Passenger(platform, gemInfo.getVersion()); } return null; } private void initServer(Class clazz, String gemName) { GemManager gemManager = platform.getGemManager(); if (gemManager == null) { return; } List<GemInfo> versions = gemManager.getVersions(gemName); GemInfo gemInfo = versions.isEmpty() ? null : versions.get(0); if (gemInfo == null) { // remove all glassfish from gems for (Iterator<RubyServer> it = servers.iterator(); it.hasNext();) { if (it.next().getClass() == clazz) { it.remove(); } } return; } RubyServer candidate = createInstance(clazz, gemInfo); if (!servers.contains(candidate)) { servers.add(candidate); } } private void initGlassFish() { if (platform.isJRuby()) { initServer(GlassFishGem.class, GlassFishGem.GEM_NAME); } } private void initTrinidad() { if (platform.isJRuby()) { initServer(Trinidad.class, Trinidad.GEM_NAME); } } private void initMongrel() { initServer(Mongrel.class, Mongrel.GEM_NAME); } private void initWEBrick() { WEBrick candidate = new WEBrick(platform); if (!servers.contains(candidate)) { servers.add(candidate); } } private void initPassenger() { initServer(Passenger.class, Passenger.GEM_NAME); } public void propertyChange(PropertyChangeEvent evt) { if (evt.getPropertyName().equals("gems")) { //NOI18N initGlassFish(); initMongrel(); initWEBrick(); ServerInstanceProviderImpl.getInstance().fireServersChanged(); } } } static class ServerComparator implements Comparator<RubyServer> { public int compare(RubyServer o1, RubyServer o2) { if (o1.getClass().equals(o2.getClass())) { return o2.getDisplayName().compareTo(o1.getDisplayName()); } if (o1 instanceof GlassFishGem) { return -1; } if (o2 instanceof GlassFishGem) { return 1; } if (o1 instanceof Mongrel) { return -1; } return 1; } } }