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

org.glassfish.admin.rest.wadl.RestModelSchemaResource Maven / Gradle / Ivy

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 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 [2019-2021] Payara Foundation and/or affiliates

package org.glassfish.admin.rest.wadl;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.TreeSet;
import java.util.logging.Level;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.xml.bind.JAXBContext;
import jakarta.xml.bind.JAXBException;
import jakarta.xml.bind.SchemaOutputResolver;
import javax.xml.transform.stream.StreamResult;
import org.glassfish.admin.rest.RestLogging;
import org.glassfish.admin.rest.composite.LegacyCompositeResource;
import org.glassfish.admin.rest.composite.RestModel;
import org.glassfish.hk2.api.ActiveDescriptor;
import org.glassfish.hk2.utilities.BuilderHelper;
import org.glassfish.internal.api.Globals;
import org.jvnet.hk2.annotations.Service;

/**
 *
 * @author jdlee
 */
@Path("/schema.xsd")
@Service
public class RestModelSchemaResource extends LegacyCompositeResource {

    @GET
    @Path("old")
    public String getSchema() throws JAXBException, IOException {
        Set> classes = new TreeSet>(new Comparator>() {
            @Override
            public int compare(Class t, Class t1) {
                return t.getName().compareTo(t1.getName());
            }
        });
        for (String c : locateRestModels()) {
            try {
                Class modelClass = loadClass(c);
                if (modelClass.getSimpleName().charAt(0) < 'C') {
                    classes.add(getCompositeUtil().getModel(modelClass).getClass());
                }
            } catch (ClassNotFoundException ex) {
                RestLogging.restLogger.log(Level.WARNING, null, ex);
            }
        }
        JAXBContext jc = JAXBContext.newInstance(classes.toArray(new Class[classes.size()]));
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        jc.generateSchema(new MySchemaOutputResolver(baos));
        return new String(baos.toByteArray());
    }

    @GET
    @Path("test1")
    public String getSchema1() throws JAXBException, IOException {
        Set> classes = new TreeSet>(new Comparator>() {
            @Override
            public int compare(Class t, Class t1) {
                return t.getName().compareTo(t1.getName());
            }
        });
        try {
            Class modelClass = loadClass("org.glassfish.admin.rest.resources.composite.Job");
            classes.add(getCompositeUtil().getModel(modelClass).getClass());
            modelClass = loadClass("org.glassfish.admin.rest.resources.composite.Dummy");
            classes.add(getCompositeUtil().getModel(modelClass).getClass());
        } catch (ClassNotFoundException ex) {
            RestLogging.restLogger.log(Level.WARNING, null, ex);
        }
        JAXBContext jc = JAXBContext.newInstance(classes.toArray(new Class[classes.size()]));
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        jc.generateSchema(new MySchemaOutputResolver(baos));
        return new String(baos.toByteArray());
    }

    @GET
    public String getSchemaManually() {
        StringBuilder sb = new StringBuilder("\n"
                + "\n");
        StringBuilder complexTypes = new StringBuilder();
        addElement(sb, "object");
        processClass(complexTypes, Object.class, "object");
        for (String c : locateRestModels()) {
            try {
                Class modelClass = getCompositeUtil().getModel(loadClass(c)).getClass();
                String simpleName = modelClass.getSimpleName().toLowerCase(Locale.getDefault());
                if (simpleName.endsWith("impl")) {
                    simpleName = simpleName.substring(0, simpleName.length() -4);
                }
                addElement(sb, simpleName);
                processClass(complexTypes, modelClass, simpleName);
            } catch (ClassNotFoundException ex) {
                RestLogging.restLogger.log(Level.WARNING, null, ex);
            }
        }
        sb.append(complexTypes);

        return sb.append("\n").toString();
    }

    /*
     * TODO: This is a bit ugly, but JAXB doesn't seem to like the way we're doing models. When
     * time permits, it may be best to revisit this and see why JAXB dies when given, for example,
     * a List or Object return type.  Once that's resolved, we may be able to use JAXB serialization.
     */
    protected void processClass(StringBuilder sb, Class c, String simpleName) {
        sb.append("\t\n\t\t\n");
        for (Class i : c.getInterfaces()) {
            for (Method m : i.getDeclaredMethods()) {
                String name = m.getName();
                if (name.startsWith("get") && !"getClass".equals(name)) {
                    name = name.substring(3, 4).toLowerCase(Locale.getDefault()) + name.substring(4);
                    Class returnType = m.getReturnType();
                    sb.append("\t\t\t)rt.getActualTypeArguments()[0];
                        sb.append(getType(returnType))
                                .append(" nillable=\"true\" minOccurs=\"0\" maxOccurs=\"unbounded\"");
                    }
                    sb.append("/>\n");
                }
            }
        }

        sb.append("\t\t\n\t\n");
    }

    private String getType(Class clazz) {
        if (clazz.isPrimitive()) {
            return "type=\"xs:" + clazz.getSimpleName() + "\"";
        } else if (WRAPPER_TYPES.contains(clazz)
                || String.class.equals(clazz)) {
            return "type=\"xs:"
                    + clazz.getSimpleName().toLowerCase(Locale.getDefault()) +"\"";
        } else {
            return "type=\"" + clazz.getSimpleName().toLowerCase(Locale.getDefault()) + "\"";
        }
    }

    private static final Set> WRAPPER_TYPES = new HashSet() {{
        add(Boolean.class);
        add(Character.class);
        add(Byte.class);
        add(Short.class);
        add(Integer.class);
        add(Long.class);
        add(Float.class);
        add(Double.class);
        add(Void.class);
    }};

    private Set locateRestModels() {
        Set classes = new HashSet();

        List> widgetDescriptors = Globals.getDefaultBaseServiceLocator()
                .getDescriptors(BuilderHelper.createContractFilter(RestModel.class.getName()));
        for (ActiveDescriptor ad : widgetDescriptors) {
            classes.add(ad.getImplementation());
        }

        return classes;
    }

    private Class loadClass(String className) throws ClassNotFoundException {
        try {
            return Thread.currentThread().getContextClassLoader().loadClass(className);
        } catch (ClassNotFoundException ex) {
            return getClass().getClassLoader().loadClass(className);
        }
    }

    private void addElement(StringBuilder sb, String simpleName) {
        sb.append("\t\n");
    }

    private static class MySchemaOutputResolver extends SchemaOutputResolver {

        ByteArrayOutputStream baos;

        public MySchemaOutputResolver(ByteArrayOutputStream baos) {
            this.baos = baos;
        }

        @Override
        public javax.xml.transform.Result createOutput(String namespaceUri, String suggestedFileName) throws IOException {
            StreamResult r = new StreamResult("argh");
            r.setOutputStream(baos);
            return r;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy