| /* |
| * Copyright (c) 2008, 2020 Oracle and/or its affiliates. All rights reserved. |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v. 2.0, which is available at |
| * http://www.eclipse.org/legal/epl-2.0. |
| * |
| * This Source Code may also be made available under the following Secondary |
| * Licenses when the conditions for such availability set forth in the |
| * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, |
| * version 2 with the GNU Classpath Exception, which is available at |
| * https://www.gnu.org/software/classpath/license.html. |
| * |
| * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 |
| */ |
| |
| package com.sun.enterprise.v3.admin.adapter; |
| |
| import com.sun.appserv.server.util.Version; |
| import com.sun.enterprise.config.serverbeans.*; |
| import com.sun.enterprise.v3.admin.AdminConsoleConfigUpgrade; |
| import java.beans.PropertyVetoException; |
| import java.io.ByteArrayOutputStream; |
| import java.io.File; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import java.net.InetAddress; |
| import java.net.URL; |
| import java.net.URLConnection; |
| import java.util.Arrays; |
| import java.util.List; |
| import java.util.Locale; |
| import java.util.MissingResourceException; |
| import java.util.ResourceBundle; |
| import java.util.concurrent.CountDownLatch; |
| import java.util.concurrent.TimeUnit; |
| import java.util.logging.Level; |
| import java.util.logging.Logger; |
| import jakarta.inject.Inject; |
| import jakarta.inject.Named; |
| import org.glassfish.api.admin.ServerEnvironment; |
| import org.glassfish.api.container.Adapter; |
| import org.glassfish.api.event.EventListener; |
| import org.glassfish.api.event.EventTypes; |
| import org.glassfish.api.event.Events; |
| import org.glassfish.api.event.RestrictTo; |
| import org.glassfish.grizzly.config.dom.NetworkListener; |
| import org.glassfish.grizzly.http.Method; |
| import org.glassfish.grizzly.http.io.OutputBuffer; |
| import org.glassfish.grizzly.http.server.HttpHandler; |
| import org.glassfish.grizzly.http.server.Request; |
| import org.glassfish.grizzly.http.server.Response; |
| import org.glassfish.hk2.api.PostConstruct; |
| import org.glassfish.hk2.api.ServiceLocator; |
| import org.glassfish.internal.data.ApplicationRegistry; |
| import org.glassfish.kernel.KernelLoggerInfo; |
| import org.glassfish.server.ServerEnvironmentImpl; |
| import org.jvnet.hk2.annotations.Service; |
| import org.jvnet.hk2.config.ConfigSupport; |
| import org.jvnet.hk2.config.SingleConfigCode; |
| import org.jvnet.hk2.config.TransactionFailure; |
| import org.jvnet.hk2.config.types.Property; |
| |
| /** |
| * An HK-2 Service that provides the functionality so that admin console access |
| * is handled properly. The general contract of this adapter is as follows: <ol> |
| * <li>This adapter is *always* installed as a Grizzly adapter for a particular |
| * URL designated as admin URL in domain.xml. This translates to context-root of |
| * admin console application. </li> <li>When the control comes to the adapter for |
| * the first time, user is asked to confirm if downloading the application is OK. |
| * In that case, the admin console application is downloaded and expanded. While |
| * the download and installation is happening, all the clients or browser |
| * refreshes get a status message. No push from the server side is attempted |
| * (yet). After the application is "installed", ApplicationLoaderService is |
| * contacted, so that the application is loaded by the containers. This |
| * application is available as a |
| * <code> system-application </code> and is persisted as such in the domain.xml. |
| * </li> <li>Even after this application is available, we don't load it on server |
| * startup by default. It is always loaded |
| * <code> on demand </code>. Hence, this adapter will always be available to |
| * find out if application is loaded and load it in the container(s) if it is |
| * not. If the application is already loaded, it simply exits. </li> </ol> |
| * |
| * @author केदार (km@dev.java.net) |
| * @author Ken Paulsen (kenpaulsen@dev.java.net) |
| * @author Siraj Ghaffar (sirajg@dev.java.net) |
| * @since GlassFish V3 (March 2008) |
| */ |
| @Service |
| public final class AdminConsoleAdapter extends HttpHandler implements Adapter, PostConstruct, EventListener { |
| |
| @Inject |
| ServerEnvironmentImpl env; |
| @Inject @Named(ServerEnvironment.DEFAULT_INSTANCE_NAME) |
| AdminService adminService; |
| private String contextRoot; |
| private File warFile; // GF Admin Console War File Location |
| private AdapterState stateMsg = AdapterState.UNINITIAZED; |
| private boolean installing = false; |
| private boolean isOK = false; // FIXME: initialize this with previous user choice |
| private AdminConsoleConfigUpgrade adminConsoleConfigUpgrade = null; |
| private final CountDownLatch latch = new CountDownLatch(1); |
| @Inject |
| ApplicationRegistry appRegistry; |
| @Inject |
| Domain domain; |
| @Inject |
| ServiceLocator habitat; |
| @Inject |
| Events events; |
| @Inject @Named(ServerEnvironment.DEFAULT_INSTANCE_NAME) |
| Config serverConfig; |
| |
| AdminEndpointDecider epd; |
| private static final Logger logger = KernelLoggerInfo.getLogger(); |
| private String statusHtml; |
| private String initHtml; |
| private boolean isRegistered = false; |
| private ResourceBundle bundle; |
| //don't change the following without changing the html pages |
| private static final String MYURL_TOKEN = "%%%MYURL%%%"; |
| private static final String STATUS_TOKEN = "%%%STATUS%%%"; |
| private static final String REDIRECT_TOKEN = "%%%LOCATION%%%"; |
| private static final String RESOURCE_PACKAGE = "com/sun/enterprise/v3/admin/adapter"; |
| private static final String INSTALL_ROOT = "com.sun.aas.installRoot"; |
| static final String ADMIN_APP_NAME = ServerEnvironmentImpl.DEFAULT_ADMIN_CONSOLE_APP_NAME; |
| private boolean isRestStarted = false; |
| private boolean isRestBeingStarted = false; |
| |
| /** |
| * Constructor. |
| */ |
| public AdminConsoleAdapter() throws IOException { |
| initHtml = Utils.packageResource2String("downloadgui.html"); |
| statusHtml = Utils.packageResource2String("status.html"); |
| } |
| |
| /** |
| * |
| */ |
| @Override |
| public String getContextRoot() { |
| return epd.getGuiContextRoot(); //default is /admin |
| } |
| |
| @Override |
| public HttpHandler getHttpService() { |
| return this; |
| } |
| |
| /** |
| * |
| */ |
| @Override |
| public void service(Request req, Response res) { |
| |
| bundle = getResourceBundle(req.getLocale()); |
| |
| Method method = req.getMethod(); |
| if (!checkHttpMethodAllowed(method)) { |
| res.setStatus(java.net.HttpURLConnection.HTTP_BAD_METHOD, |
| method.getMethodString() + " " + bundle.getString("http.bad.method")); |
| res.setHeader("Allow", getAllowedHttpMethodsAsString()); |
| return; |
| } |
| if (!env.isDas()) { |
| sendStatusNotDAS(req, res); |
| return; |
| } |
| |
| //This is needed to support the case where user update to 3.1 from previous release, and didn't run the upgrade tool. |
| if (adminConsoleConfigUpgrade == null) { |
| adminConsoleConfigUpgrade = habitat.getService(AdminConsoleConfigUpgrade.class); |
| } |
| |
| try { |
| if (!latch.await(100L, TimeUnit.SECONDS)) { |
| // todo : better error reporting. |
| logger.log(Level.SEVERE, KernelLoggerInfo.consoleRequestTimeout); |
| return; |
| } |
| } catch (InterruptedException ex) { |
| logger.log(Level.SEVERE, KernelLoggerInfo.consoleCannotProcess); |
| return; |
| } |
| logRequest(req); |
| if (isResourceRequest(req)) { |
| try { |
| handleResourceRequest(req, res); |
| } catch (IOException ioe) { |
| if (logger.isLoggable(Level.SEVERE)) { |
| logger.log(Level.SEVERE, KernelLoggerInfo.consoleResourceError, |
| new Object[]{req.getRequestURI(), ioe.toString()}); |
| } |
| if (logger.isLoggable(Level.FINE)) { |
| logger.log(Level.FINE, |
| ioe.toString(), |
| ioe); |
| } |
| } |
| return; |
| } |
| res.setContentType("text/html; charset=UTF-8"); |
| |
| // simple get request use via javascript to give back the console status (starting with :::) |
| // as a simple string. |
| // see usage in status.html |
| |
| |
| String serverVersion = Version.getFullVersion(); |
| |
| if ("/testifbackendisready.html".equals(req.getRequestURI())) { |
| |
| // Replace state token |
| String status = getStateMsg().getI18NKey(); |
| try { |
| // Try to get a localized version of this key |
| status = bundle.getString(status); |
| } catch (MissingResourceException ex) { |
| // Use the non-localized String version of the status |
| status = getStateMsg().toString(); |
| } |
| String wkey = AdapterState.WELCOME_TO.getI18NKey(); |
| try { |
| // Try to get a localized version of this key |
| serverVersion = bundle.getString(wkey) + " " + serverVersion + "."; |
| } catch (MissingResourceException ex) { |
| // Use the non-localized String version of the status |
| serverVersion = AdapterState.WELCOME_TO.toString() + " " + serverVersion + "."; |
| } |
| status += "\n" + serverVersion; |
| try { |
| OutputBuffer ob = getOutputBuffer(res); |
| |
| byte[] bytes = (":::" + status).getBytes("UTF-8"); |
| res.setContentLength(bytes.length); |
| ob.write(bytes, 0, bytes.length); |
| ob.flush(); |
| |
| } catch (IOException ex) { |
| logger.log(Level.SEVERE, KernelLoggerInfo.consoleResourceError, ex); |
| } |
| |
| |
| return; |
| } |
| if (isApplicationLoaded()) { |
| // Let this pass to the admin console (do nothing) |
| handleLoadedState(); |
| } else { |
| // if the admin console is not loaded, and someone use the REST access, |
| //browsers also request the favicon icon... Since we do not want to load |
| // the admin gui just to return a non existing icon, |
| //we just return without loading the entire console... |
| if ("/favicon.ico".equals(req.getRequestURI())) { |
| return; |
| } |
| if (!isRestStarted) { |
| forceRestModuleLoad(req); |
| } |
| synchronized(this) { |
| if (isInstalling()) { |
| sendStatusPage(req, res); |
| } else { |
| if (isApplicationLoaded()) { |
| // Double check here that it is not yet loaded (not |
| // likely, but possible) |
| handleLoadedState(); |
| }else { |
| loadConsole(); |
| sendStatusPage(req, res); |
| } |
| } |
| } |
| |
| } |
| |
| } |
| |
| void loadConsole() { |
| try { |
| // We have permission and now we should install |
| // (or load) the application. |
| setInstalling(true); |
| startThread(); // Thread must set installing false |
| } catch (Exception ex) { |
| // Ensure we haven't crashed with the installing |
| // flag set to true (not likely). |
| setInstalling(false); |
| throw new RuntimeException( |
| "Unable to install Admin Console!", ex); |
| } |
| } |
| |
| /** |
| * @param req the Request |
| * @return <code>true</code> if the request is for a resource with a known content |
| * type otherwise <code>false</code>. |
| */ |
| private boolean isResourceRequest(Request req) { |
| return (getContentType(req.getRequestURI()) != null); |
| } |
| |
| /** |
| * All that needs to happen for the REST module to be initialized is a request |
| * of some sort. Here, we don't care about the response, so we make the request |
| * then close the stream and move on. |
| */ |
| private void forceRestModuleLoad(final Request req) { |
| if (isRestBeingStarted==true){ |
| return; |
| } |
| isRestBeingStarted = true; |
| Thread thread = new Thread("Force REST Module Load Thread") { |
| @Override |
| public void run() { |
| initRest(); |
| } |
| }; |
| thread.setDaemon(true); |
| thread.start(); |
| } |
| |
| private String getContentType(String resource) { |
| |
| if (resource == null || resource.length() == 0) { |
| return null; |
| } |
| // this may need to be expanded upon the future, in which case, the |
| // current implementation may not be worth maintaining |
| if (resource.endsWith(".gif")) { |
| return "image/gif"; |
| } else if (resource.endsWith(".jpg")) { |
| return "image/jpeg"; |
| } else { |
| if (logger.isLoggable(Level.FINE)) { |
| logger.log(Level.FINE, "Unhandled content-type: {0}", resource); |
| } |
| return null; |
| } |
| |
| } |
| |
| private void handleResourceRequest(Request req, Response res) |
| throws IOException { |
| |
| String resourcePath = RESOURCE_PACKAGE + req.getRequestURI(); |
| |
| ClassLoader loader = AdminConsoleAdapter.class.getClassLoader(); |
| |
| InputStream in = null; |
| try { |
| in = loader.getResourceAsStream(resourcePath); |
| if (in == null) { |
| logger.log(Level.WARNING, KernelLoggerInfo.consoleResourceNotFound, resourcePath); |
| return; |
| } |
| byte[] buf = new byte[512]; |
| ByteArrayOutputStream baos = new ByteArrayOutputStream(512); |
| for (int i = in.read(buf); i != -1; i = in.read(buf)) { |
| baos.write(buf, 0, i); |
| } |
| String contentType = getContentType(resourcePath); |
| if (contentType != null) { |
| res.setContentType(contentType); |
| } |
| res.setContentLength(baos.size()); |
| OutputStream out = res.getOutputStream(); |
| baos.writeTo(out); |
| out.flush(); |
| |
| } finally { |
| if (in != null) { |
| in.close(); |
| } |
| } |
| |
| } |
| |
| boolean isApplicationLoaded() { |
| return (stateMsg == AdapterState.APPLICATION_LOADED); |
| } |
| |
| /** |
| * |
| */ |
| boolean isInstalling() { |
| return installing; |
| } |
| |
| /** |
| * |
| */ |
| void setInstalling(boolean flag) { |
| installing = flag; |
| } |
| |
| /** |
| * Checks whether this adapter has been registered as a network endpoint. |
| */ |
| @Override |
| public boolean isRegistered() { |
| return isRegistered; |
| } |
| |
| /** |
| * Marks this adapter as having been registered or unregistered as a |
| * network endpoint |
| */ |
| @Override |
| public void setRegistered(boolean isRegistered) { |
| this.isRegistered = isRegistered; |
| } |
| |
| /** |
| * <p> This method sets the current state.</p> |
| */ |
| void setStateMsg(AdapterState msg) { |
| stateMsg = msg; |
| logger.log(Level.FINE, msg.toString()); |
| } |
| |
| /** |
| * <p> This method returns the current state, which will be one of the |
| * valid values defined by {@link AdapterState}.</p> |
| */ |
| AdapterState getStateMsg() { |
| return stateMsg; |
| } |
| |
| /** |
| * |
| */ |
| @Override |
| public void postConstruct() { |
| events.register(this); |
| //set up the environment properly |
| init(); |
| } |
| |
| /** |
| * |
| */ |
| @Override |
| public void event(@RestrictTo(EventTypes.SERVER_READY_NAME) Event event) { |
| latch.countDown(); |
| if (logger != null) { |
| logger.log(Level.FINE, "AdminConsoleAdapter is ready."); |
| } |
| } |
| |
| /** |
| * |
| */ |
| private void init() { |
| Property locProp = adminService.getProperty(ServerTags.ADMIN_CONSOLE_DOWNLOAD_LOCATION); |
| if (locProp == null || locProp.getValue() == null || locProp.getValue().equals("")) { |
| String iRoot = System.getProperty(INSTALL_ROOT) + "/lib/install/applications/admingui.war"; |
| warFile = new File(iRoot.replace('/', File.separatorChar)); |
| writeAdminServiceProp(ServerTags.ADMIN_CONSOLE_DOWNLOAD_LOCATION, "${" + INSTALL_ROOT + "}/lib/install/applications/admingui.war"); |
| } else { |
| //For any non-absolute path, we start from the installation, ie glassfish7 |
| //eg, v3 prelude upgrade, where the location property was "glassfish/lib..." |
| String locValue = locProp.getValue(); |
| warFile = new File(locValue); |
| if (!warFile.isAbsolute()) { |
| File tmp = new File(System.getProperty(INSTALL_ROOT), ".."); |
| warFile = new File(tmp, locValue); |
| } |
| } |
| |
| if (logger.isLoggable(Level.FINE)) { |
| logger.log(Level.FINE, "Admin Console download location: {0}", warFile.getAbsolutePath()); |
| } |
| |
| initState(); |
| |
| try { |
| epd = new AdminEndpointDecider(serverConfig); |
| contextRoot = epd.getGuiContextRoot(); |
| } catch (Exception ex) { |
| logger.log(Level.INFO, KernelLoggerInfo.consoleCannotInitialize, ex); |
| return; |
| } |
| } |
| |
| void initRest() { |
| InputStream is = null; |
| try { |
| NetworkListener nl = domain.getServerNamed("server").getConfig().getNetworkConfig() |
| .getNetworkListener("admin-listener"); |
| SecureAdmin secureAdmin = habitat.getService(SecureAdmin.class); |
| |
| URL url = new URL( |
| (SecureAdmin.Util.isEnabled(secureAdmin) ? "https" : "http"), |
| nl.getAddress(), |
| Integer.parseInt(nl.getPort()), |
| "/management/domain"); |
| URLConnection conn = url.openConnection(); |
| is = conn.getInputStream(); |
| isRestStarted = true; |
| } catch (Exception ex) { |
| logger.log(Level.FINE, null, ex); |
| } finally { |
| if (is != null) { |
| try { |
| is.close(); |
| } catch (IOException ex1) { |
| logger.log(Level.FINE, null, ex1); |
| } |
| } |
| } |
| } |
| |
| |
| /** |
| * |
| */ |
| private void initState() { |
| // It is a given that the application is NOT loaded to begin with |
| if (appExistsInConfig()) { |
| isOK = true; // FIXME: I don't think this is good enough |
| setStateMsg(AdapterState.APPLICATION_INSTALLED_BUT_NOT_LOADED); |
| } else if (new File(warFile.getParentFile(), ADMIN_APP_NAME).exists() || warFile.exists()) { |
| // The exploded dir, or the .war exists... mark as downloded |
| if (logger.isLoggable(Level.FINE)) { |
| setStateMsg(AdapterState.DOWNLOADED); |
| } |
| isOK = true; |
| } else { |
| setStateMsg(AdapterState.APPLICATION_NOT_INSTALLED); |
| } |
| } |
| |
| /** |
| * |
| */ |
| private boolean appExistsInConfig() { |
| return (getConfig() != null); |
| } |
| |
| /** |
| * |
| */ |
| Application getConfig() { |
| //no application-ref logic here -- that's on purpose for now |
| Application app = domain.getSystemApplicationReferencedFrom(env.getInstanceName(), ADMIN_APP_NAME); |
| |
| return app; |
| } |
| |
| /** |
| * |
| */ |
| private void logRequest(Request req) { |
| if (logger.isLoggable(Level.FINE)) { |
| logger.log(Level.FINE, "AdminConsoleAdapter''s STATE IS: {0}", getStateMsg()); |
| logger.log(Level.FINE, "Current Thread: {0}", Thread.currentThread().getName()); |
| for (final String name : req.getParameterNames()) { |
| final String values = Arrays.toString(req.getParameterValues(name)); |
| logger.log(Level.FINE, "Parameter name: {0} values: {1}", new Object[]{name, values}); |
| } |
| } |
| } |
| |
| /** |
| * |
| */ |
| enum InteractionResult { |
| |
| OK, |
| CANCEL, |
| FIRST_TIMER; |
| } |
| |
| /** |
| * <p> Determines if the user has permission.</p> |
| */ |
| private boolean hasPermission(InteractionResult ir) { |
| //do this quickly as this is going to block the grizzly worker thread! |
| //check for returning user? |
| if (ir == InteractionResult.OK) { |
| isOK = true; |
| } |
| return isOK; |
| } |
| |
| /** |
| * |
| */ |
| private void startThread() { |
| new InstallerThread(this, habitat, domain, env, contextRoot, epd.getGuiHosts()).start(); |
| } |
| |
| /** |
| * |
| */ |
| /* |
| private synchronized InteractionResult getUserInteractionResult(GrizzlyRequest req) { |
| if (req.getParameter(OK_PARAM) != null) { |
| proxyHost = req.getParameter(PROXY_HOST_PARAM); |
| if ((proxyHost != null) && !proxyHost.equals("")) { |
| String ps = req.getParameter(PROXY_PORT_PARAM); |
| try { |
| proxyPort = Integer.parseInt(ps); |
| } catch (NumberFormatException nfe) { |
| throw new IllegalArgumentException( |
| "The specified proxy port (" + ps |
| + ") must be a valid port integer!", nfe); |
| } |
| } |
| // FIXME: I need to "remember" this answer in a persistent way!! Or it will popup this message EVERY time after the server restarts. |
| setStateMsg(AdapterState.PERMISSION_GRANTED); |
| isOK = true; |
| return InteractionResult.OK; |
| } else if (req.getParameter(CANCEL_PARAM) != null) { |
| // Canceled |
| // FIXME: I need to "remember" this answer in a persistent way!! Or it will popup this message EVERY time after the server restarts. |
| setStateMsg(AdapterState.CANCELED); |
| isOK = false; |
| return InteractionResult.CANCEL; |
| } |
| |
| // This is a first-timer |
| return InteractionResult.FIRST_TIMER; |
| } |
| * |
| */ |
| private OutputBuffer getOutputBuffer(Response res) { |
| res.setStatus(202); |
| res.setContentType("text/html"); |
| res.setCharacterEncoding("UTF-8"); |
| return res.getOutputBuffer(); |
| } |
| |
| /** |
| * |
| */ |
| private void sendStatusPage(Request req, Response res) { |
| byte[] bytes; |
| try { |
| OutputBuffer ob = getOutputBuffer(res); |
| // Replace locale specific Strings |
| String localHtml = replaceTokens(statusHtml, bundle); |
| |
| // Replace state token |
| String status = getStateMsg().getI18NKey(); |
| try { |
| // Try to get a localized version of this key |
| status = bundle.getString(status); |
| } catch (MissingResourceException ex) { |
| // Use the non-localized String version of the status |
| status = getStateMsg().toString(); |
| } |
| String locationUrl = req.getScheme() |
| + "://" + req.getServerName() |
| + ':' + req.getServerPort() + "/login.jsf"; |
| localHtml = localHtml.replace(REDIRECT_TOKEN, locationUrl); |
| bytes = localHtml.replace(STATUS_TOKEN, status).getBytes("UTF-8"); |
| res.setContentLength(bytes.length); |
| ob.write(bytes, 0, bytes.length); |
| ob.flush(); |
| } catch (IOException ex) { |
| throw new RuntimeException(ex); |
| } |
| } |
| |
| /** |
| * |
| */ |
| private void sendStatusNotDAS(Request req, Response res) { |
| byte[] bytes; |
| try { |
| String html = Utils.packageResource2String("statusNotDAS.html"); |
| OutputBuffer ob = getOutputBuffer(res); |
| // Replace locale specific Strings |
| String localHtml = replaceTokens(html, bundle); |
| |
| bytes = localHtml.getBytes("UTF-8"); |
| res.setContentLength(bytes.length); |
| ob.write(bytes, 0, bytes.length); |
| ob.flush(); |
| } catch (IOException ex) { |
| throw new RuntimeException(ex); |
| } |
| } |
| |
| /** |
| * <p> This method returns the resource bundle for localized Strings used |
| * by the AdminConsoleAdapter.</p> |
| * |
| * @param locale The Locale to be used. |
| */ |
| private ResourceBundle getResourceBundle(Locale locale) { |
| return ResourceBundle.getBundle( |
| "com.sun.enterprise.v3.admin.adapter.LocalStrings", locale); |
| } |
| |
| /** |
| * <p> This method replaces all tokens in text with values from the given |
| * <code>ResourceBundle</code>. A token starts and ends with 3 |
| * percent (%) characters. The value between the percent characters |
| * will be used as the key to the given <code>ResourceBundle</code>. |
| * If a key does not exist in the bundle, no substitution will take |
| * place for that token.</p> |
| * |
| * @return The same text except with substituted tokens when available. |
| * @param text The text containing tokens to be replaced. |
| * @param bundle The <code>ResourceBundle</code> with keys for the value |
| */ |
| private String replaceTokens(String text, ResourceBundle bundle) { |
| int start = 0, end = 0; |
| String newString = null; |
| StringBuilder buf = new StringBuilder(""); |
| |
| while (start != -1) { |
| // Find start of token |
| start = text.indexOf("%%%", end); |
| if (start != -1) { |
| // First copy the stuff before the start |
| buf.append(text.substring(end, start)); |
| |
| // Move past the %%% |
| start += 3; |
| |
| // Find end of token |
| end = text.indexOf("%%%", start); |
| if (end != -1) { |
| try { |
| // Copy the token value to the buffer |
| buf.append( |
| bundle.getString(text.substring(start, end))); |
| } catch (MissingResourceException ex) { |
| // Unable to find the resource, so we don't do anything |
| buf.append("%%%").append(text.substring(start, end)).append("%%%"); |
| } |
| |
| // Move past the %%% |
| end += 3; |
| } else { |
| // Add back the %%% because we didn't find a matching end |
| buf.append("%%%"); |
| |
| // Reset end so we can copy the remainder of the text |
| end = start; |
| } |
| } |
| } |
| |
| // Copy the remainder of the text |
| buf.append(text.substring(end)); |
| |
| // Return the new String |
| return buf.toString(); |
| } |
| |
| public AdminService getAdminService() { |
| return adminService; |
| } |
| |
| private void writeAdminServiceProp(final String propName, final String propValue) { |
| try { |
| ConfigSupport.apply(new SingleConfigCode<AdminService>() { |
| |
| @Override |
| public Object run(AdminService adminService) throws PropertyVetoException, TransactionFailure { |
| Property newProp = adminService.createChild(Property.class); |
| adminService.getProperty().add(newProp); |
| newProp.setName(propName); |
| newProp.setValue(propValue); |
| return newProp; |
| } |
| }, adminService); |
| } catch (Exception ex) { |
| logger.log(Level.WARNING, KernelLoggerInfo.consoleCannotWriteProperty, |
| new Object[] {propName, propValue, ex}); |
| } |
| } |
| |
| /** |
| * |
| */ |
| private void handleLoadedState() { |
| //System.out.println(" Handle Loaded State!!"); |
| // do nothing |
| statusHtml = null; |
| initHtml = null; |
| } |
| |
| @Override |
| public int getListenPort() { |
| return epd.getListenPort(); |
| } |
| |
| @Override |
| public InetAddress getListenAddress() { |
| return epd.getListenAddress(); |
| } |
| |
| @Override |
| public List<String> getVirtualServers() { |
| return epd.getGuiHosts(); |
| } |
| // enum HttpMethod { |
| // OPTIONS ("OPTIONS"), |
| // GET ("GET"), |
| // HEAD ("HEAD"), |
| // POST ("POST"), |
| // PUT ("PUT"), |
| // DELETE ("DELETE"), |
| // TRACE ("TRACE"), |
| // CONNECT ("CONNECT"); |
| // |
| // private String method; |
| // |
| // HttpMethod(String method) { |
| // this.method = method; |
| // } |
| // |
| // static HttpMethod getHttpMethod(String httpMethod) { |
| // for (HttpMethod hh: HttpMethod.values()) { |
| // if (hh.method.equalsIgnoreCase(httpMethod)) { |
| // return hh; |
| // } |
| // } |
| // return null; |
| // } |
| // |
| // String method() { |
| // return method; |
| // } |
| // } |
| private final Method[] allowedHttpMethods = {Method.GET, Method.POST, Method.HEAD, |
| Method.DELETE, Method.PUT}; |
| |
| private boolean checkHttpMethodAllowed(Method method) { |
| for (Method hh : allowedHttpMethods) { |
| if (hh.equals(method)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| private String getAllowedHttpMethodsAsString() { |
| StringBuilder sb = new StringBuilder(allowedHttpMethods[0].getMethodString()); |
| for (int i = 1; i < allowedHttpMethods.length; i++) { |
| sb.append(", ").append(allowedHttpMethods[i].getMethodString()); |
| } |
| return sb.toString(); |
| } |
| } |