All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.glassfish.admin.rest.utils.ResourceUtil Maven / Gradle / Ivy

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 2009-2013 Oracle and/or its affiliates. All rights reserved.
 *
 * 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
 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  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 packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * 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.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * 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 don't 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.
 */
 
// Portions Copyright [2016-2021] [Payara Foundation and/or its affiliates]

package org.glassfish.admin.rest.utils;

import com.sun.enterprise.config.serverbeans.Config;
import com.sun.enterprise.config.serverbeans.Domain;
import com.sun.enterprise.universal.xml.MiniXmlParser.JvmOption;

import fish.payara.audit.AdminAuditService;
import fish.payara.asadmin.recorder.AsadminRecorderService;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLDecoder;
import java.security.AccessController;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import javax.security.auth.Subject;
import javax.security.auth.login.LoginException;
import jakarta.ws.rs.core.HttpHeaders;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.MultivaluedMap;
import jakarta.ws.rs.core.PathSegment;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.UriInfo;
import org.glassfish.admin.rest.Constants;
import org.glassfish.admin.rest.RestLogging;
import org.glassfish.admin.rest.generator.CommandResourceMetaData;
import org.glassfish.admin.rest.provider.MethodMetaData;
import org.glassfish.admin.rest.provider.ParameterMetaData;
import org.glassfish.admin.rest.provider.ProviderUtil;
import static org.glassfish.admin.rest.provider.ProviderUtil.getElementLink;
import org.glassfish.admin.rest.results.ActionReportResult;
import static org.glassfish.admin.rest.utils.Util.eleminateHypen;
import static org.glassfish.admin.rest.utils.Util.getHtml;
import static org.glassfish.admin.rest.utils.Util.methodNameFromDtdName;
import org.glassfish.admin.rest.utils.xml.RestActionReporter;
import org.glassfish.admin.restconnector.RestConfig;
import org.glassfish.api.ActionReport;
import org.glassfish.api.Param;
import org.glassfish.api.admin.AdminCommand;
import org.glassfish.api.admin.CommandModel;
import org.glassfish.api.admin.CommandRunner;
import org.glassfish.api.admin.CommandRunner.CommandInvocation;
import org.glassfish.api.admin.ParameterMap;
import org.glassfish.api.admin.RestRedirect;
import org.glassfish.api.admin.RestRedirects;
import org.glassfish.grizzly.http.server.Request;
import org.glassfish.hk2.api.MultiException;
import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.internal.api.AdminAccessController;
import org.glassfish.internal.api.Globals;
import org.glassfish.jersey.media.sse.EventOutput;
import org.glassfish.security.services.api.authorization.AuthorizationService;
import org.glassfish.security.services.common.PrivilegedLookup;

import org.jvnet.hk2.config.Attribute;
import org.jvnet.hk2.config.ConfigBeanProxy;
import org.jvnet.hk2.config.ConfigModel;
import org.jvnet.hk2.config.Dom;
import org.jvnet.hk2.config.DomDocument;

/**
 * Resource utilities class. Used by resource templates,
 * TemplateListOfResource and
 * TemplateRestResource
 *
 * @author Rajeshwar Patil
 */
public class ResourceUtil {
    private static final String DAS_LOOK_FOR_CERT_PROPERTY_NAME = "org.glassfish.admin.DASCheckAdminCert";
    private static final String MESSAGE_PARAMETERS = "messageParameters";
    private static final String DEFAULT = "DEFAULT";
    
    private static RestConfig restConfig = null;
    // TODO: this is copied from org.jvnet.hk2.config.Dom. If we are not able to encapsulate the conversion in Dom,
    // need to make sure that the method convertName is refactored into smaller methods such that trimming of prefixes
    // stops. We will need a promotion of HK2 for this.
    static final Pattern TOKENIZER;
    
    private static final Logger LOGGER = Logger.getLogger(ResourceUtil.class.getPackage().toString());
    
    static {
        String pattern = or(
                split("x", "X"), // AbcDef -> Abc|Def
                split("X", "Xx"), // USArmy -> US|Army
                //split("\\D","\\d"), // SSL2 -> SSL|2
                split("\\d", "\\D") // SSL2Connector -> SSL|2|Connector
                );
        pattern = pattern.replace("x", "\\p{Lower}").replace("X", "\\p{Upper}");
        TOKENIZER = Pattern.compile(pattern);
    }

    protected static byte[] getBytesFromStream(final InputStream is) {
        final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
        byte[] bytes = null;
        int nRead;
        byte[] data = new byte[16384];
        try {
            while ((nRead = is.read(data, 0, data.length)) != -1) {
                buffer.write(data, 0, nRead);
            }
            buffer.flush();
            bytes = buffer.toByteArray();
            buffer.close();
        } catch (IOException ex) {
            RestLogging.restLogger.log(Level.SEVERE, RestLogging.IO_EXCEPTION, ex.getMessage());
        }

        return bytes;
    }

    private ResourceUtil() {
    }

    /**
     * Adjust the input parameters. In case of POST and DELETE methods, user can
     * provide name, id or DEFAULT parameter for primary parameter(i.e the
     * object to create or delete). This method is used to rename primary
     * parameter name to DEFAULT irrespective of what user provides.
     */
    public static void adjustParameters(Map data) {
        if (data != null && !(data.containsKey(DEFAULT))) {
                boolean isRenamed = renameParameter(data, "id", DEFAULT);
                if (!isRenamed) {
                    renameParameter(data, "name", DEFAULT);
                }
        }
    }

    /**
     * Adjust the input parameters. In case of POST and DELETE methods, user can
     * provide id or DEFAULT parameter for primary parameter(i.e the object to
     * create or delete). This method is used to rename primary parameter name
     * to DEFAULT irrespective of what user provides.
     */
    public static void defineDefaultParameters(Map data) {
        if (data != null && !(data.containsKey(DEFAULT))) {
                renameParameter(data, "id", DEFAULT);
        }
    }

    /**
     * Returns the name of the command associated with this resource,if any, for
     * the given operation.
     *
     * @param type the given resource operation
     * @return String the associated command name for the given operation.
     */
    public static String getCommand(RestRedirect.OpType type, ConfigModel model) {

        Class cbp = null;
        try {
            cbp = (Class) model.classLoaderHolder.loadClass(model.targetTypeName);
        } catch (MultiException e) {
            LOGGER.log(Level.SEVERE, null, e);
        }

        if (cbp != null) {
            RestRedirects restRedirects = cbp.getAnnotation(RestRedirects.class);
            if (restRedirects != null) {
                RestRedirect[] values = restRedirects.value();
                for (RestRedirect r : values) {
                    if (r.opType().equals(type)) {
                        return r.commandName();
                    }
                }
            }
        }
        return null;
    }

    /**
     * Executes the specified __asadmin command.
     * @param commandName
     * @param parameters
     * @param subject
     * @return
     */
    public static RestActionReporter runCommand(String commandName,
                                                ParameterMap parameters,
                                                Subject subject) {
        return runCommand(commandName, parameters, subject, false);
    }

    /**
     * Executes the specified __asadmin command.
     * @param commandName
     * @param parameters
     * @param subject
     * @param managedJob
     * @return
     */
    public static RestActionReporter runCommand(String commandName,
                                                ParameterMap parameters,
                                                Subject subject,
                                                boolean managedJob) {            
        AsadminRecorderService asadminRecorderService = Globals.get(AsadminRecorderService.class);
        if (asadminRecorderService != null && asadminRecorderService.isEnabled()) {
            asadminRecorderService.recordAsadminCommand(commandName, 
                                                        parameters);
        }
        
        AdminAuditService auditService = Globals.getDefaultHabitat().getService(AdminAuditService.class);
        if (auditService != null && auditService.isEnabled()) {
            auditService.recordAsadminCommand(commandName, parameters, subject);
        }

        CommandRunner cr = Globals.getDefaultHabitat().getService(CommandRunner.class);
        RestActionReporter ar = new RestActionReporter();
        final CommandInvocation commandInvocation = cr.getCommandInvocation(commandName, ar, subject);
        if (managedJob) {
            commandInvocation.managedJob();
        }
        commandInvocation.parameters(parameters).execute();
        addCommandLog(ar, commandName, parameters);

        return ar;
    }

    /**
     * Executes the specified __asadmin command.
     *
     * @param commandName the command to execute
     * @param parameters the command parameters
     * @param subject Subject
     * @return ActionReport object with command execute status details.
     */
    public static RestActionReporter runCommand(String commandName,
                                                Map parameters,
                                                Subject subject) {
        ParameterMap p = new ParameterMap();
        for (Map.Entry entry : parameters.entrySet()) {
            p.set(entry.getKey(), entry.getValue());
        }

        return runCommand(commandName, p, subject);
    }

    public static EventOutput runCommandWithSse(final String commandName,
                                                final ParameterMap parameters,
                                                final Subject subject,
                                                final SseCommandHelper.ActionReportProcessor processor) {
        CommandRunner cr = Globals.getDefaultHabitat().getService(CommandRunner.class);
        final RestActionReporter ar = new RestActionReporter();
        final CommandInvocation commandInvocation =
            cr.getCommandInvocation(commandName, ar, subject).
            parameters(parameters);
        return SseCommandHelper.invokeAsync(commandInvocation,
                    new SseCommandHelper.ActionReportProcessor() {
                            @Override
                            public ActionReport process(ActionReport report, EventOutput ec) {
                                addCommandLog(ar, commandName, parameters);
                                if (processor != null) {
                                    return processor.process(report, ec);
                                }
                                return ar;
                            }
                        });
    }


    public static void addCommandLog(RestActionReporter ar, String commandName, ParameterMap parameters) {
        List logs = (List) ar.getExtraProperties().get("commandLog");
        if (logs == null) {
            logs = new ArrayList();
            ar.getExtraProperties().put("commandLog", logs);
        }
        final String parameterList = encodeString(getParameterList(parameters));

        logs.add(commandName + parameterList);
    }

    public static String encodeString(String text) {
        if (text == null) {
            return "";
        }
        String result = text.replaceAll("<", "<").replaceAll(">", ">");
        result = result.replaceAll("eval\\((.*)\\)", "");
        result = result.replaceAll("[\\\"\\\'][\\s]*((?i)javascript):(.*)[\\\"\\\']", "\"\"");
        result = result.replaceAll("((?i)script)", "");
        return result;
    }

    public static String getParameterList(ParameterMap parameters) {
        StringBuilder sb = new StringBuilder();

        for (Map.Entry> entry : parameters.entrySet()) {
            String paramName = entry.getKey();
            for (String param : entry.getValue()) {
                sb.append(" --").append(paramName).append(" ").append(param);
            }
        }

        return sb.toString();
    }

    /**
     * Constructs and returns the resource method meta-data.
     *
     * @param command the command associated with the resource method
     * @param habitat the habitat
     * @return MethodMetaData the meta-data store for the resource method.
     */
    public static MethodMetaData getMethodMetaData(String command, ServiceLocator habitat) {
        return getMethodMetaData(command, null, habitat);
    }

    /**
     * Constructs and returns the resource method meta-data.
     *
     * @param command the command associated with the resource method
     * @param commandParamsToSkip the command parameters for which not to
     * include the meta-data.
     * @param habitat the habitat
     * @return MethodMetaData the meta-data store for the resource method.
     */
    public static MethodMetaData getMethodMetaData(String command, Map commandParamsToSkip,
            ServiceLocator habitat) {
        MethodMetaData methodMetaData = new MethodMetaData();

        if (command != null) {
            Collection params;
            if (commandParamsToSkip == null) {
                params = getParamMetaData(command, habitat);
            } else {
                params = getParamMetaData(command, commandParamsToSkip.keySet(), habitat);
            }

            if (params != null) {
                Iterator iterator = params.iterator();
                CommandModel.ParamModel paramModel;
                while (iterator.hasNext()) {
                    paramModel = iterator.next();
                    Param param = paramModel.getParam();
                    ParameterMetaData parameterMetaData = getParameterMetaData(paramModel);

                    String parameterName = (param.primary()) ? "id" : paramModel.getName();

                    // If the Param has an alias, use it instead of the name
                    String alias = param.alias();
                    if (alias != null && (!alias.isEmpty())) {
                        parameterName = alias;
                    }


                    methodMetaData.putParameterMetaData(parameterName, parameterMetaData);
                }
            }
        }

        return methodMetaData;
    }

    public static void resolveParamValues(Map commandParams, UriInfo uriInfo) {
        List pathSegments = uriInfo.getPathSegments();
        Map processParams = new HashMap();
        processParams.putAll(commandParams);

        for (Map.Entry entry : commandParams.entrySet()) {
            String value = entry.getValue();
            if (value.equals(Constants.VAR_PARENT)) {
                processParams.put(entry.getKey(), pathSegments.get(pathSegments.size() - 2).getPath());
            } else if (value.startsWith(Constants.VAR_GRANDPARENT)) {
                int number =
                        (value.equals(Constants.VAR_GRANDPARENT))
                        ? 1 : // no number given
                        Integer.parseInt(value.substring(Constants.VAR_GRANDPARENT.length()));

                processParams.put(entry.getKey(), pathSegments.get(pathSegments.size() - (number + 2)).getPath());
            }
        }

        commandParams.clear();
        commandParams.putAll(processParams);
    }

    /**
     * Constructs and returns the resource method meta-data. This method is
     * called to get meta-data in case of update method (POST).
     *
     * @param configBeanModel the config bean associated with the resource.
     * @return MethodMetaData the meta-data store for the resource method.
     */
    public static MethodMetaData getMethodMetaData(ConfigModel configBeanModel) {
        MethodMetaData methodMetaData = new MethodMetaData();

        Class configBeanProxy = null;
        try {
            configBeanProxy = (Class) configBeanModel.classLoaderHolder
                    .loadClass(configBeanModel.targetTypeName);

            Set attributeNames = configBeanModel.getAttributeNames();
            for (String attributeName : attributeNames) {
                String methodName = getAttributeMethodName(attributeName);
                Method method = null;
                try {
                    method = configBeanProxy.getMethod(methodName);
                } catch (NoSuchMethodException e) {
                    // Method not found, so let's try a brute force method if the method
                    // can't be found via the method above.  For example: for
                    // Ssl.getSSLInactivityTimeout(), we calculate getSslInactivityTimeout,
                    // which doesn't match due to case.
                    String booleanMethodName = getAttributeBooleanMethodName(attributeName);
                    for (Method m : configBeanProxy.getMethods()) {
                        if (m.getName().equalsIgnoreCase(methodName)
                                || m.getName().equalsIgnoreCase(booleanMethodName)) {
                            method = m;
                        }
                    }
                }
                Attribute attribute = method.getAnnotation(Attribute.class);
                if (attribute != null) {
                    ParameterMetaData parameterMetaData = getParameterMetaData(attribute);
                    if (method.getAnnotation(Deprecated.class) != null) {
                        parameterMetaData.putAttribute(Constants.DEPRECATED, "true");
                    }

                    //camelCase the attributeName before passing out
                    attributeName = eleminateHypen(attributeName);

                    methodMetaData.putParameterMetaData(attributeName, parameterMetaData);

                }
            }
        } catch (MultiException e) {
            LOGGER.log(Level.SEVERE, null, e);
        }

        return methodMetaData;
    }

    public static MethodMetaData getMethodMetaData2(Dom parent, ConfigModel childModel, int parameterType) {
        MethodMetaData methodMetaData = new MethodMetaData();
        List> interfaces = new ArrayList>();
        Map params = new HashMap();

        try {
            Class configBeanProxy =
                    (Class) childModel.classLoaderHolder.loadClass(childModel.targetTypeName);
            getInterfaces(configBeanProxy, interfaces);

            Set attributeNames = childModel.getAttributeNames();
            for (String attributeName : attributeNames) {
                String methodName = ResourceUtil.getAttributeMethodName(attributeName);

                //camelCase the attributeName before passing out
                attributeName = Util.eleminateHypen(attributeName);

                ParameterMetaData parameterMetaData = params.get(attributeName);
                if (parameterMetaData == null) {
                    parameterMetaData = new ParameterMetaData();
                    params.put(attributeName, parameterMetaData);
                }
                // Check parent interfaces
                for (int i = interfaces.size() - 1; i >= 0; i--) {
                    Class intf = interfaces.get(i);
                    try {
                        Method method = intf.getMethod(methodName);
                        Attribute attribute = method.getAnnotation(Attribute.class);
                        if (attribute != null) {
                            ParameterMetaData localParam = ResourceUtil.getParameterMetaData(attribute);
                            copyParameterMetaDataAttribute(localParam, parameterMetaData, Constants.DEFAULT_VALUE);
                            copyParameterMetaDataAttribute(localParam, parameterMetaData, Constants.KEY);
                            copyParameterMetaDataAttribute(localParam, parameterMetaData, Constants.TYPE);
                            copyParameterMetaDataAttribute(localParam, parameterMetaData, Constants.OPTIONAL);
                        }
                    } catch (NoSuchMethodException e) {
                    }
                }

                // Check ConfigBean
                try {
                    Method method = configBeanProxy.getMethod(methodName);
                    Attribute attribute = method.getAnnotation(Attribute.class);
                    if (attribute != null) {
                        ParameterMetaData localParam = ResourceUtil.getParameterMetaData(attribute);
                        copyParameterMetaDataAttribute(localParam, parameterMetaData, Constants.DEFAULT_VALUE);
                        copyParameterMetaDataAttribute(localParam, parameterMetaData, Constants.KEY);
                        copyParameterMetaDataAttribute(localParam, parameterMetaData, Constants.TYPE);
                        copyParameterMetaDataAttribute(localParam, parameterMetaData, Constants.OPTIONAL);
                    }
                } catch (NoSuchMethodException e) {
                }


                methodMetaData.putParameterMetaData(attributeName, parameterMetaData);

            }
        } catch (MultiException cnfe) {
            throw new RuntimeException(cnfe);
        }

        return methodMetaData;
    }

    protected static void copyParameterMetaDataAttribute(ParameterMetaData from, ParameterMetaData to, String key) {
        if (from.getAttributeValue(key) != null) {
            to.putAttribute(key, from.getAttributeValue(key));
        }
    }

    protected static void getInterfaces(Class clazz, List> interfaces) {
        for (Class intf : clazz.getInterfaces()) {
            interfaces.add(intf);
            getInterfaces(intf, interfaces);
        }
    }

    /*
     * test if a command really exists in the current runningVM
     */
    public static boolean commandIsPresent(ServiceLocator habitat, String commandName) {
        try {
            habitat.getService(AdminCommand.class, commandName);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * Constructs and returns the parameter meta-data.
     *
     * @param commandName the command associated with the resource method
     * @param habitat the habitat
     * @return Collection the meta-data for the parameter of the resource
     * method.
     */
    public static Collection getParamMetaData(
            String commandName, ServiceLocator habitat) {
        final CommandModel model = habitat.getService(CommandRunner.class).getModel(commandName, RestLogging.restLogger);
        if (model == null) {
            return null;
        }

        return model.getParameters();
    }

    /**
     * Constructs and returns the parameter meta-data.
     *
     * @param commandName the command associated with the resource method
     * @param commandParamsToSkip the command parameters for which not to
     * include the meta-data.
     * @param habitat the habitat
     * @return Collection the meta-data for the parameter of the resource
     * method.
     */
    public static Collection getParamMetaData(
            String commandName, Collection commandParamsToSkip,
            ServiceLocator habitat) {
        CommandModel cm = habitat.getService(CommandRunner.class).getModel(commandName, RestLogging.restLogger);
        Collection parameterNames = cm.getParametersNames();

        ArrayList metaData = new ArrayList();
        CommandModel.ParamModel paramModel;
        for (String name : parameterNames) {
            paramModel = cm.getModelFor(name);
            String parameterName = (paramModel.getParam().primary()) ? "id" : paramModel.getName();

            if (!commandParamsToSkip.contains(parameterName)) {
                metaData.add(paramModel);
            }
        }

        return metaData;
    }

    /**
     * Removes entries with empty value from the given Map
     * @param data  data to remove empty entries from
     */
    public static void purgeEmptyEntries(Map data) {

        //hack-2 : remove empty entries if the form has a hidden param for __remove_empty_entries__
        if ("true".equals(data.get("__remove_empty_entries__"))) {
            data.remove("__remove_empty_entries__");
            //findbug
            for (Iterator> i = data.entrySet().iterator(); i.hasNext();) {
                Map.Entry entry = i.next();
                String value = entry.getValue();
                if ((value == null) || (value.length() < 1)) {
                    i.remove();
                }
            }
        }
    }

    /**
     * Constructs and returns the appropriate response object based on the
     * client.
     *
     * @param status the http status code for the response
     * @param message message for the response
     * @param requestHeaders request headers of the request
     * @return Response the response object to be returned to the client
     */
    public static Response getResponse(int status, String message, HttpHeaders requestHeaders, UriInfo uriInfo) {
        if (isBrowser(requestHeaders)) {
            message = getHtml(message, uriInfo, false);
        }
        return Response.status(status).entity(message).build();
    }

    public static ActionReportResult getActionReportResult(ActionReport.ExitCode status, String message, HttpHeaders requestHeaders, UriInfo uriInfo) {
        RestActionReporter ar = new RestActionReporter();
        ar.setActionExitCode(status);
        return getActionReportResult(ar, message, requestHeaders, uriInfo);
    }

    public static ActionReportResult getActionReportResult(RestActionReporter ar, String message, HttpHeaders requestHeaders, UriInfo uriInfo) {
        if (isBrowser(requestHeaders)) {
            message = getHtml(message, uriInfo, false);
        }
        ActionReport.ExitCode status = ar.getActionExitCode();
        ActionReportResult result = new ActionReportResult(ar);

        if (status != ActionReport.ExitCode.SUCCESS && status != ActionReport.ExitCode.WARNING) {
            result.setErrorMessage(message);
            result.setIsError(true);
        }

        ar.setActionExitCode(status);
        ar.setMessage(message);
        return result;
    }

    /**
     * special case for the delete operation: we need to give back the URI of
     * the parent since the resource we are on is deleted
     *
     * @param status
     * @param message
     * @param requestHeaders
     * @param uriInfo
     * @return
     */
    // FIXME: This doesn't do what the javadoc says it should
    public static Response getDeleteResponse(int status, String message,
            HttpHeaders requestHeaders, UriInfo uriInfo) {
        if (isBrowser(requestHeaders)) {
            message = getHtml(message, uriInfo, true);
        }
        return Response.status(status).entity(message).build();
    }

    /**
     * 

This method takes any query string parameters and adds them to the * specified map. This is used, for example, with the delete operation when * cascading deletes are required:

DELETE http://localhost:4848/.../foo?cascade=true *

The reason we need to use query parameters versus "body" variables is * the limitation that HttpURLConnection has in this regard. * * @param data */ public static void addQueryString(MultivaluedMap qs, Map data) { for (Map.Entry> entry : qs.entrySet()) { String key = entry.getKey(); for (String value : entry.getValue()) { try { data.put(URLDecoder.decode(key, "UTF-8"), URLDecoder.decode(value, "UTF-8")); // TODO: Last one wins? Can't imagine we'll see List.size() > 1, but... } catch (UnsupportedEncodingException ex) { throw new RuntimeException(ex); } } } } public static void addQueryString(MultivaluedMap qs, Properties data) { for (Map.Entry> entry : qs.entrySet()) { String key = entry.getKey(); for (String value : entry.getValue()) { data.put(key, value); // TODO: Last one wins? Can't imagine we'll see List.size() > 1, but... } } } //Construct parameter meta-data from the model static ParameterMetaData getParameterMetaData(CommandModel.ParamModel paramModel) { Param param = paramModel.getParam(); ParameterMetaData parameterMetaData = new ParameterMetaData(); parameterMetaData.putAttribute(Constants.TYPE, getXsdType(paramModel.getType().toString())); parameterMetaData.putAttribute(Constants.OPTIONAL, Boolean.toString(param.optional())); String val = param.defaultValue(); if ((val != null) && (!val.equals("\u0000"))) { parameterMetaData.putAttribute(Constants.DEFAULT_VALUE, param.defaultValue()); } parameterMetaData.putAttribute(Constants.ACCEPTABLE_VALUES, param.acceptableValues()); return parameterMetaData; } //Construct parameter meta-data from the attribute annotation static ParameterMetaData getParameterMetaData(Attribute attribute) { ParameterMetaData parameterMetaData = new ParameterMetaData(); parameterMetaData.putAttribute(Constants.TYPE, getXsdType(attribute.dataType().toString())); parameterMetaData.putAttribute(Constants.OPTIONAL, Boolean.toString(!attribute.required())); if (!(attribute.defaultValue().equals("\u0000"))) { parameterMetaData.putAttribute(Constants.DEFAULT_VALUE, attribute.defaultValue()); } parameterMetaData.putAttribute(Constants.KEY, Boolean.toString(attribute.key())); //FIXME - Currently, Attribute class does not provide acceptable values. //parameterMetaData.putAttribute(Contants.ACCEPTABLE_VALUES, // getXsdType(attribute.acceptableValues())); return parameterMetaData; } //rename the given input parameter private static boolean renameParameter(Map data, String parameterToRename, String newName) { if ((data.containsKey(parameterToRename))) { String value = data.get(parameterToRename); data.remove(parameterToRename); data.put(newName, value); return true; } return false; } //returns true only if the request is from browser private static boolean isBrowser(HttpHeaders requestHeaders) { boolean isClientAcceptsHtml = false; MediaType media = requestHeaders.getMediaType(); java.util.List acceptHeaders = requestHeaders.getRequestHeader(HttpHeaders.ACCEPT); for (String header : acceptHeaders) { if (header.contains(MediaType.TEXT_HTML)) { isClientAcceptsHtml = true; break; } } return media != null && (media.equals(MediaType.APPLICATION_FORM_URLENCODED_TYPE)) && (isClientAcceptsHtml); } private static String getXsdType(String javaType) { if (javaType.contains(Constants.JAVA_STRING_TYPE)) { return Constants.XSD_STRING_TYPE; } if (javaType.contains(Constants.JAVA_BOOLEAN_TYPE)) { return Constants.XSD_BOOLEAN_TYPE; } if (javaType.contains(Constants.JAVA_INT_TYPE)) { return Constants.XSD_INT_TYPE; } if (javaType.contains(Constants.JAVA_PROPERTIES_TYPE)) { return Constants.XSD_PROPERTIES_TYPE; } return javaType; } public static String getAttributeMethodName(String attributeName) { return methodNameFromDtdName(attributeName, "get"); } public static String getAttributeBooleanMethodName(String attributeName) { return methodNameFromDtdName(attributeName, "is"); } private static String split(String lookback, String lookahead) { return "((?<=" + lookback + ")(?=" + lookahead + "))"; } private static String or(String... tokens) { StringBuilder buf = new StringBuilder(); for (String t : tokens) { if (buf.length() > 0) { buf.append('|'); } buf.append(t); } return buf.toString(); } public static String convertToXMLName(String name) { // tokenize by finding 'x|X' and 'X|Xx' then insert '-'. StringBuilder buf = new StringBuilder(name.length() + 5); for (String t : TOKENIZER.split(name)) { if (buf.length() > 0) { buf.append('-'); } buf.append(t.toLowerCase(Locale.US)); } return buf.toString(); } /** * @return A copy of given * sourceData where key of each entry from it is converted to * xml name */ public static Map translateCamelCasedNamesToXMLNames(Map sourceData) { HashMap convertedData = new HashMap(sourceData.size()); for (Map.Entry entry : sourceData.entrySet()) { String camelCasedKeyName = entry.getKey(); String xmlKeyName = convertToXMLName(camelCasedKeyName); convertedData.put(xmlKeyName, entry.getValue()); } return convertedData; } /* * we try to prefer html by default for all browsers (safari, chrome, * firefox). Same if the request is asking for "*" among all the possible * AcceptableMediaTypes */ public static String getResultType(HttpHeaders requestHeaders) { String result = "html"; String firstOne = null; List lmt = requestHeaders.getAcceptableMediaTypes(); for (MediaType mt : lmt) { if (mt.getSubtype().equals("html")) { return result; } if (mt.getSubtype().equals("*")) { return result; } if (firstOne == null) { //default to the first one if many are there. firstOne = mt.getSubtype(); } } if (firstOne != null) { return firstOne; } else { return result; } } public static Map buildMethodMetadataMap(MethodMetaData mmd) { // yuck Map map = new TreeMap(); Set params = mmd.parameters(); Iterator iterator = params.iterator(); String param; while (iterator.hasNext()) { param = iterator.next(); ParameterMetaData parameterMetaData = mmd.getParameterMetaData(param); map.put(param, processAttributes(parameterMetaData.attributes(), parameterMetaData)); } return map; } private static Map processAttributes(Set attributes, ParameterMetaData parameterMetaData) { Map pmdm = new HashMap(); Iterator attriter = attributes.iterator(); String attributeName; while (attriter.hasNext()) { attributeName = attriter.next(); String attributeValue = parameterMetaData.getAttributeValue(attributeName); pmdm.put(attributeName, attributeValue); } return pmdm; } /* * REST can now be configured via RestConfig to show or hide the deprecated * elements and attributes @return true if this model is deprecated */ public static boolean isDeprecated(ConfigModel model) { try { Class cbp = (Class) model.classLoaderHolder.loadClass(model.targetTypeName); Deprecated dep = cbp.getAnnotation(Deprecated.class); return dep != null; } catch (MultiException e) { LOGGER.log(Level.SEVERE, null, e); } return false; } public static Map getResourceLinks(Dom dom, UriInfo uriInfo, boolean canShowDeprecated) { Map links = new TreeMap(); for (String elementName : dom.model.getElementNames()) { //for each element if (elementName.equals("*")) { ConfigModel.Node node = (ConfigModel.Node) dom.model.getElement(elementName); ConfigModel childModel = node.getModel(); List lcm = getRealChildConfigModels(childModel, dom.document); Collections.sort(lcm, new ConfigModelComparator()); if (lcm != null) { for (ConfigModel cmodel : lcm) { if ((!isDeprecated(cmodel) || canShowDeprecated)) { links.put(cmodel.getTagName(), ProviderUtil.getElementLink(uriInfo, cmodel.getTagName())); } } } } else { ConfigModel.Property childElement = dom.model.getElement(elementName); boolean deprec = false; if (childElement instanceof ConfigModel.Node) { ConfigModel.Node node = (ConfigModel.Node) childElement; deprec = isDeprecated(node.getModel()); } for (String annotation : childElement.getAnnotations()) { if (annotation.equals(Deprecated.class.getName())) { deprec = true; } } if ((!deprec || canShowDeprecated)) { links.put(elementName, ProviderUtil.getElementLink(uriInfo, elementName)); } } } String beanName = getUnqualifiedTypeName(dom.model.targetTypeName); for (CommandResourceMetaData cmd : CommandResourceMetaData.getCustomResourceMapping(beanName)) { links.put(cmd.resourcePath, ProviderUtil.getElementLink(uriInfo, cmd.resourcePath)); } return links; } /** * @param qualifiedTypeName * @return unqualified type name for given qualified type name. This is a * substring of qualifiedTypeName after last "." */ public static String getUnqualifiedTypeName(String qualifiedTypeName) { return qualifiedTypeName.substring(qualifiedTypeName.lastIndexOf('.') + 1, qualifiedTypeName.length()); } public static boolean isOnlyATag(ConfigModel model) { return (model.getAttributeNames().isEmpty()) && (model.getElementNames().isEmpty()); } public static List getRealChildConfigModels(ConfigModel childModel, DomDocument domDocument) { List retlist = new ArrayList(); try { Class subType = childModel.classLoaderHolder.loadClass(childModel.targetTypeName); List list = domDocument.getAllModelsImplementing(subType); if (list != null) { for (ConfigModel el : list) { if (isOnlyATag(el)) { //this is just a tag element retlist.addAll(getRealChildConfigModels(el, domDocument)); } else { retlist.add(el); } } } else {//https://glassfish.dev.java.net/issues/show_bug.cgi?id=12654 if (!isOnlyATag(childModel)) { //this is just a tag element retlist.add(childModel); } } } catch (ClassNotFoundException e) { throw new RuntimeException(e); } return retlist; } /** * @param model * @return name of the key attribute for the given model. */ private static String getKey(Dom model) { String key = model.getKey(); if (key == null) { for (String s : model.getAttributeNames()) {//no key, by default use the name attr if (s.equals("name")) { key = model.attribute(s); } } if (key == null)//nothing, so pick the first one { Set attributeNames = model.getAttributeNames(); if (!attributeNames.isEmpty()) { key = model.attribute(attributeNames.iterator().next()); } else { //TODO carried forward from old generator. Should never reach here. But we do for ConfigExtension and WebModuleConfig key = "ThisIsAModelBug:NoKeyAttr"; //no attr choice fo a key!!! Error!!! key = ""; } } } return key; } public static Map getResourceLinks(List proxyList, UriInfo uriInfo) { Map links = new TreeMap(); Collections.sort(proxyList, new DomConfigurator()); for (Dom proxy : proxyList) { //for each element try { links.put( getKey(proxy), getElementLink(uriInfo, getKey(proxy))); } catch (Exception e) { throw new RuntimeException(e); } } return links; } public static List> getCommandLinks(String[][] commandResourcesPaths) { List> commands = new ArrayList>(); for (String[] array : commandResourcesPaths) { Map command = new HashMap(); command.put("command", array[0]); command.put("method", array[1]); command.put("path", array[2]); commands.add(command); } return commands; } public static void addMethodMetaData(ActionReport ar, Map mmd) { List methodMetaData = new ArrayList(); MethodMetaData getMetaData = mmd.get("GET"); methodMetaData.add(new HashMap() { { put("name", "GET"); } }); if (getMetaData != null) { //are they extra params for a GET command? Map getMetaDataMap = new HashMap(); if (getMetaData.sizeParameterMetaData() > 0) { getMetaDataMap.put(MESSAGE_PARAMETERS, buildMethodMetadataMap(getMetaData)); } methodMetaData.add(getMetaDataMap); } MethodMetaData postMetaData = mmd.get("POST"); Map postMetaDataMap = new HashMap(); if (postMetaData != null) { postMetaDataMap.put("name", "POST"); // if (postMetaData.sizeQueryParamMetaData() > 0) { // postMetaDataMap.put(QUERY_PARAMETERS, buildMethodMetadataMap(postMetaData, true)); // } if (postMetaData.sizeParameterMetaData() > 0) { postMetaDataMap.put(MESSAGE_PARAMETERS, buildMethodMetadataMap(postMetaData)); } methodMetaData.add(postMetaDataMap); } MethodMetaData deleteMetaData = mmd.get("DELETE"); if (deleteMetaData != null) { Map deleteMetaDataMap = new HashMap(); deleteMetaDataMap.put("name", "DELETE"); deleteMetaDataMap.put(MESSAGE_PARAMETERS, buildMethodMetadataMap(deleteMetaData)); methodMetaData.add(deleteMetaDataMap); } ar.getExtraProperties().put("methods", methodMetaData); } public static synchronized RestConfig getRestConfig(ServiceLocator habitat) { if (restConfig == null) { if (habitat == null) { return null; } Domain domain = Globals.getDefaultBaseServiceLocator().getService(Domain.class); if (domain != null) { Config config = domain.getConfigNamed("server-config"); if (config != null) { restConfig = config.getExtensionByType(RestConfig.class); } } } return restConfig; } /* * returns true if the HTML viewer displays the deprecated elements or * attributes of a config bean */ public static boolean canShowDeprecatedItems(ServiceLocator habitat) { RestConfig rg = getRestConfig(habitat); return (rg != null) && (rg.getShowDeprecatedItems().equalsIgnoreCase("true")); } /** * Authenticate the given req as originated from given remoteHost against * admin realm. * * @return subject identifying the user/client */ public static Subject authenticateViaAdminRealm(ServiceLocator habitat, Request req, String remoteHost) throws LoginException, IOException { Subject subject = null; final AdminAccessController authenticator = habitat.getService(AdminAccessController.class); if (authenticator != null) { // This is temporary workaround for a Grizzly issue that prohibits uploading (deploy) files larger than 2MB when secure admin is enabled. // The workaround will not be required in trunk when the corresponding Grizzly issue is fixed. // Please see http://java.net/jira/browse/GLASSFISH-16665 for details // The workaround duplicates code from AdminAdapter. subject = authenticator.loginAsAdmin(req, remoteHost); } return subject; } /** * Indicates whether the subject can perform the action on the resource. * * @param habitat ServiceLocator for finding services * @param subject the Subject to be qualified * @param resource the resource affected by the action * @param action the action being attempted by the subject on the resource * @return true if the subject is allowed to perform the action, false otherwise * @throws URISyntaxException */ public static boolean isAuthorized(final ServiceLocator habitat, final Subject subject, final String resource, final String action) throws URISyntaxException { final AuthorizationService authorizationSvc = AccessController.doPrivileged( new PrivilegedLookup(habitat, AuthorizationService.class)); return authorizationSvc.isAuthorized(subject, new URI("admin", resource, null), action); } /** * Creates a new rearranged map of JVM options. Options {@code target} and {@code profiler} are forwarded 1:1. All * other options are joined in the result map for key {@code id} and are separated by semi-colon. * * An input key may include a value. In such case key and value are divided by an equals sign: {@code key=value}. In * case of an empty value the key may end with an equals sign: {@code key=}. If the value is given as part of the * key the input value should be empty or {@code null}. A value may itself contain equals signs. * * Keys ending with a backslash the backslash is stripped away. This is a backwards compatibility behaviour * addressing remains of escaped equals sign that isn't properly unescaped prior to splitting in all path. * * The resulting option only uses an equals sign between key and value in case the value is non-empty. This is * independent of whether the value was extracted from the input key or input value. * * @param jvmOptions a set of jvm options given as key-value pairs, keys are allowed to contain values too * @param removeVersioning set {@code true} to erase any JVM version prefix from the keys, {@code false} to keep * keys as they are. * @return a map where most options are joined into one expression for key {@code id}. If existing {@code target} * and {@code profiler} keys are kept same as in input map. */ public static Map processJvmOptions(Map jvmOptions, boolean removeVersioning) { Map results = new HashMap<>(); StringBuilder options = new StringBuilder(); String sep = ""; for (Map.Entry option : jvmOptions.entrySet()) { String key = option.getKey(); if ("target".equals(key) || "profiler".equals(key)) { results.put(key, option.getValue()); } else if (key != null && !key.trim().isEmpty()) { int endOfKey = key.indexOf('='); String value = null; if (endOfKey > 0) { value = key.substring(endOfKey + 1); key = key.substring(0, endOfKey); } if (key.endsWith("\\")) { key = key.substring(0, key.length() - 1); } options.append(sep); options.append(removeVersioning ? new JvmOption(key).option : key); if (value == null || value.trim().isEmpty()) { value = option.getValue(); } if (value != null && !value.trim().isEmpty()) { options.append("=").append(value); } sep = ":"; } } results.put("id", options.toString()); return results; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy