org.glassfish.admingui.common.handlers.PluginHandlers Maven / Gradle / Ivy
Show all versions of payara-embedded-all Show documentation
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-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.
*/
package org.glassfish.admingui.common.handlers;
import com.sun.jsftemplating.annotation.Handler;
import com.sun.jsftemplating.annotation.HandlerInput;
import com.sun.jsftemplating.annotation.HandlerOutput;
import com.sun.jsftemplating.component.ComponentUtil;
import com.sun.jsftemplating.layout.LayoutDefinitionManager;
import com.sun.jsftemplating.layout.LayoutViewHandler;
import com.sun.jsftemplating.layout.descriptors.ComponentType;
import com.sun.jsftemplating.layout.descriptors.LayoutComponent;
import com.sun.jsftemplating.layout.descriptors.LayoutDefinition;
import com.sun.jsftemplating.layout.descriptors.handler.HandlerContext;
import com.sun.jsftemplating.util.FileUtil;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.servlet.ServletContext;
import org.glassfish.admingui.common.factories.NavigationNodeFactory;
import org.glassfish.admingui.common.util.GuiUtil;
import org.glassfish.admingui.plugin.ConsolePluginService;
import org.glassfish.admingui.connector.IntegrationPoint;
import org.glassfish.admingui.plugin.IntegrationPointComparator;
import org.glassfish.hk2.api.ServiceLocator;
/**
* This class will provide JSFTemplating Handler
s that
* provide access to {@link IntegrationPoint}s and possibily other
* information / services needed to provide plugin functionality
* i.e. getting resources, etc.).
*
* @author Ken Paulsen ([email protected])
*/
public class PluginHandlers {
// NOTE: This file used to exist at: v3/admingui/core/src/main/java/org/glassfish/handlers/PluginHandlers.java.
/**
* Constructor.
*/
protected PluginHandlers() {
}
/**
* Find and return the ConsolePluginService
. This method
* uses the HK2 Habitat
to locate the
* ConsolePluginService
.
*
* @param ctx The FacesContext
.
*
* @returns The ConsolePluginService
.
*/
public static ConsolePluginService getPluginService(FacesContext ctx) {
// We need to get the ServletContext to find the Habitat
ServletContext servletCtx = (ServletContext)
(ctx.getExternalContext()).getContext();
// Get the Habitat from the ServletContext
ServiceLocator habitat = (ServiceLocator) servletCtx.getAttribute(
org.glassfish.admingui.common.plugin.ConsoleClassLoader.HABITAT_ATTRIBUTE);
// System.out.println("Habitat:" + habitat);
return habitat.getService(ConsolePluginService.class);
}
/**
* This handler returns a
* Map<String id, List<URL>>
containing all
* the matches of the requested resource. Each List
in
* the Map
is associated with a GUI Plugin, and the key
* to the Map
is the plugin id.
*
* @param handlerCtx The HandlerContext
.
*/
@Handler(id="getPluginResources",
input={
@HandlerInput(name="name", type=String.class, required=true)},
output={
@HandlerOutput(name="resources", type=Map.class)})
public static void getPluginResources(HandlerContext handlerCtx) {
String name = (String) handlerCtx.getInputValue("name");
ConsolePluginService cps = getPluginService(
handlerCtx.getFacesContext());
handlerCtx.setOutputValue("resources", cps.getResources(name));
}
/**
* This handler provides access to {@link IntegrationPoint}s for the
* requested key.
*
* @param handlerCtx The HandlerContext
.
*/
@Handler(id="getIntegrationPoints",
input={
@HandlerInput(name="type", type=String.class, required=true)},
output={
@HandlerOutput(name="points", type=List.class)})
public static void getIntegrationPoints(HandlerContext handlerCtx) {
String type = (String) handlerCtx.getInputValue("type");
List value =
getIntegrationPoints(handlerCtx.getFacesContext(), type);
handlerCtx.setOutputValue("points", value);
}
/**
*
*/
public static List getIntegrationPoints(FacesContext context, String type) {
return getPluginService(context).getIntegrationPoints(type);
}
/**
* This handler adds {@link IntegrationPoint}s of a given type to a
* UIComponent
tree. It looks for
* {@link IntegrationPoint}s using the given type
. It
* then sorts the results (if any) by parentId
, and then
* by priority. It next interates over each one looking for a
* UIComponent
with an id
which matches the
* its own parentId
value. It then uses the content of
* the {@link IntegrationPoint} to attempt to include the .jsf page
* it refers to under the identified parent component.
*/
@Handler(id="includeIntegrations",
input={
@HandlerInput(name="type", type=String.class, required=true),
@HandlerInput(name="root", type=UIComponent.class, required=false)})
public static void includeIntegrations(HandlerContext handlerCtx) {
// Get the input
String type = (String) handlerCtx.getInputValue("type");
UIComponent root = (UIComponent) handlerCtx.getInputValue("root");
try{
// Get the IntegrationPoints
FacesContext ctx = handlerCtx.getFacesContext();
List points = getIntegrationPoints(ctx, type);
// Include them
includeIntegrationPoints(ctx, root, getSortedIntegrationPoints(points));
}catch(Exception ex){
GuiUtil.getLogger().severe("Error in includeIntegrations ; \ntype = " + type + "; root=" + root.toString());
if (GuiUtil.getLogger().isLoggable(Level.FINE)){
ex.printStackTrace();
}
}
}
/**
* Includes the first IP based on priority for the given type. It adds
* the content to the given UIComponent root. If the IP content looks
* like a URL (contains ://), a StaticText component will be added with
* the value of the content from the URL.
*/
@Handler(id="includeFirstIntegrationPoint",
input={
@HandlerInput(name="type", type=String.class, required=true),
@HandlerInput(name="root", type=UIComponent.class, required=false)})
public static void includeFirstIntegrationPoint(HandlerContext handlerCtx) throws java.io.IOException {
// Get the input
String type = (String) handlerCtx.getInputValue("type");
UIComponent root = (UIComponent) handlerCtx.getInputValue("root");
// Get the IntegrationPoints
FacesContext ctx = handlerCtx.getFacesContext();
Set points =
getSortedIntegrationPoints(getIntegrationPoints(ctx, type));
if (points != null) {
Iterator it = points.iterator();
if (it.hasNext()) {
// Get the first one...
IntegrationPoint point = it.next();
root = getIntegrationPointParent(ctx, root, point);
// Check to see if IP points to an external URL...
if (point.getContent().lastIndexOf("://", 15) != -1) {
// Treat content as a url...
URL contentURL = FileUtil.searchForFile(
point.getContent(), null);
if (contentURL == null) {
throw new IOException("Unable to locate file: "
+ point.getContent());
}
// Read the content...
String content = new String(FileUtil.readFromURL(contentURL));
// Create a StaticText component and add it under the
// "root" component.
LayoutComponent stDesc = new LayoutComponent(null,
"externalContent", new ComponentType("tmpTextCT",
"com.sun.jsftemplating.component.factory.basic.StaticTextFactory"));
stDesc.addOption("value", content);
ComponentUtil.getInstance(ctx).createChildComponent(ctx, stDesc, root);
} else {
// Include the first one...
includeIntegrationPoint(ctx, root, point);
}
}
}
}
/**
* Finds the integration point of the specified type. Returns the contents of this IP type as a list.
* The content can be a comma separated String.
* This is useful for the case such as dropdown or list box to allow additional options in the component.
*/
@Handler(id="getContentOfIntegrationPoints",
input={
@HandlerInput(name="type", type=String.class, required=true)},
output={
@HandlerOutput(name="labels", type=List.class),
@HandlerOutput(name="values", type=List.class)})
public static void getContentOfIntegrationPoints(HandlerContext handlerCtx) throws java.io.IOException {
// Get the input
String type = (String) handlerCtx.getInputValue("type");
// Get the IntegrationPoints
FacesContext ctx = handlerCtx.getFacesContext();
Set points = getSortedIntegrationPoints(getIntegrationPoints(ctx, type));
List labels = new ArrayList();
List values = new ArrayList();
if (points != null) {
for(IntegrationPoint it : points){
String content = it.getContent();
if (GuiUtil.isEmpty(content)){
GuiUtil.getLogger().warning("No Content specified for Integration Point: " + type + " id : " + it.getId());
continue;
}
List labelsAndValues = GuiUtil.parseStringList(content, "|");
values.add(labelsAndValues.get(0));
labels.add(GuiUtil.getMessage(labelsAndValues.get(1), labelsAndValues.get(2)));
}
}
handlerCtx.setOutputValue("labels", labels);
handlerCtx.setOutputValue("values", values);
}
@Handler(id="getAppEditIntegrationPoint",
input={
@HandlerInput(name="type", type=String.class, required=true)},
output={
@HandlerOutput(name="appEditPageMap", type=Map.class)})
public static void getAppEditIntegrationPoint(HandlerContext handlerCtx) throws java.io.IOException {
// Get the input
String type = (String) handlerCtx.getInputValue("type");
// Get the IntegrationPoints
FacesContext ctx = handlerCtx.getFacesContext();
Set points = getSortedIntegrationPoints(getIntegrationPoints(ctx, type));
Map result = new HashMap();
if (points != null) {
for(IntegrationPoint it : points){
String content = it.getContent();
if (GuiUtil.isEmpty(content)){
GuiUtil.getLogger().warning("No Content specified for Integration Point: " + type + " id : " + it.getId());
continue;
}
List vv = GuiUtil.parseStringList(content, ":");
if (vv.size()!=2){
GuiUtil.getLogger().warning("Invalid content specified for Integration Point: " + type + " id : " + it.getId());
continue;
}
result.put(vv.get(0), vv.get(1));
}
}
handlerCtx.setOutputValue("appEditPageMap", result);
}
/**
* This method sorts the given {@link IntegrationPoint}'s by parentId
* and then by priority. It returns a SortedSet
of the
* results with the ABC order parentId. When parentId's match, the
* highest piority will appear first.
*/
public static Set getSortedIntegrationPoints(List points) {
// Make sure we have something...
if (points == null) {
return null;
}
// Use a TreeSet to sort automatically
Set sortedSet =
new TreeSet(
IntegrationPointComparator.getInstance());
// FIXME: Check for duplicates! Modify "id" if there is a duplicate?
sortedSet.addAll(points);
return sortedSet;
}
/**
*
* @param points This parameter should be the {@link IntegrationPoint}s
* to include in the order in which you want to include
* them if that matters (i.e. use SortedSet
).
*/
public static void includeIntegrationPoints(FacesContext ctx, UIComponent root, Set points) {
if (points == null) {
// Do nothing...
return;
}
if (root == null) {
// No root is specified, search whole page
root = ctx.getViewRoot();
}
// Iterate
IntegrationPoint point;
Iterator it = null;
int lastSize = 0;
int currSize = points.size();
String parentId = null;
String lastParentId = null;
while (currSize != lastSize) {
// Stop loop by comparing previous size
lastSize = currSize;
it = points.iterator();
lastParentId = "";
UIComponent parent = root;
// Iterate through the IntegrationPoints
while (it.hasNext()) {
point = it.next();
// Optimize for multiple plugins for the same parent
parentId = point.getParentId();
// Resolve any EL that may be used in identifying the parent ID
parentId = (String) ComponentUtil.getInstance(ctx).resolveValue(ctx, null, root, parentId);
if ((parentId == null) || !parentId.equals(lastParentId)) {
// New parent (or root -- null)
parent = getIntegrationPointParent(ctx, root, point);
}
if (parent == null) {
// Didn't find the one specified!
// FIXME: log FINE! Note this may not be a problem, keep iterating to see if we find it later.
//System.out.println("The specified parentId (" + parentId + ") was not found!");
lastParentId = null;
continue;
}
lastParentId = parent.getId();
// Add the content
includeIntegrationPoint(ctx, parent, point);
// We found the parent, remove from our list of IPs to add
it.remove();
}
// Get the set size to see if we have any left to process
currSize = points.size();
}
}
/**
* This method returns the parent for the content of the given
* {@link IntegrationPoint}.
*
* @param root The UIComponent
in which to search for
* the parent.
* @param point The {@link IntegrationPoint} which is looking for its
* parent UIComponent
.
*/
public static UIComponent getIntegrationPointParent(FacesContext ctx, UIComponent root, IntegrationPoint point) {
UIComponent parent = null;
String parentId = point.getParentId();
parentId = (String) ComponentUtil.getInstance(ctx).resolveValue(ctx, null, root, parentId);
if (parentId == null) {
// If not specified, just stick it @ the root
//parentId = root.getId();
parent = root;
} else {
parent = findComponentById(root, parentId);
}
// Return the IntegrationPoint parent
return parent;
}
/**
* This method includes a single {@link IntegrationPoint} under the
* given parent UIComponent
.
*
* @param ctx The FacesContext
.
* @param parent The parent for the {@link IntegrationPoint}.
* @param point The {@link IntegrationPoint}.
*/
public static void includeIntegrationPoint(FacesContext ctx, UIComponent parent, IntegrationPoint point) {
// Add the content
String content = point.getContent();
while (content.startsWith("/")) {
content = content.substring(1);
}
String key = content;
if (!key.contains("://")) {
key = "/" + point.getConsoleConfigId() + "/" + content;
}
LayoutDefinition def = LayoutDefinitionManager.getLayoutDefinition(ctx, key);
LayoutViewHandler.buildUIComponentTree(ctx, parent, def);
}
/**
* This method search for the requested simple id in the given
* UIComponent
. If the id matches the UIComponent, it
* is returned, otherwise, it will search the children and facets
* recursively.
*
* @param base The UIComponent
to search.
* @param id The id
we're looking for.
*
* @return The UIComponent, or null.
*/
private static UIComponent findComponentById(UIComponent base, String id) {
// Check if this is the one we're looking for
if (id.equals(base.getId())) {
return base;
}
// Not this one, check its kids
Iterator it = base.getFacetsAndChildren();
UIComponent comp = null;
while (it.hasNext()) {
// Recurse
comp = findComponentById(it.next(), id);
if (comp != null) {
// Found!
return comp;
}
}
// Not found
return null;
}
/**
* This handler is used for the navigation nodes that request content
* from an external URL. This handler pulls the "real url" from from
* the component specified by the compId
parameter (this
* necessarily depends on the presence of the navigation container in
* the view for the component look up to work). Once the component
* has been found, the url is retrieved from the attribute map, and
* its contents retrieved. If processPage
is true, the
* URL contents are interpretted and the resulting component(s) are
* added to the component tree (This feature is not currently
* supported).. Otherwise, the contents are returned in the output
* parameter pluginPage
to be output as-is on the
* page.
*
* @param handlerCtx The HandlerContext
.
*/
@Handler(id = "retrievePluginPageContents",
input = {@HandlerInput(name = "compId", type = String.class, required = true)},
output = {@HandlerOutput(name = "pluginPage", type = String.class)})
public static void retrievePluginPageContents(HandlerContext handlerCtx) {
String id = (String) handlerCtx.getInputValue("compId");
UIComponent comp = handlerCtx.getFacesContext().getViewRoot().findComponent(id);
String urlContents = "";
if (comp != null) {
String url = (String) comp.getAttributes().get(NavigationNodeFactory.REAL_URL);
try {
// Read from the URL...
URL contentUrl = FileUtil.searchForFile(url, null);
if (contentUrl == null) {
throw new IOException("Unable to locate file: " + url);
}
urlContents = new String(FileUtil.readFromURL(contentUrl));
// FIXME: Implement processPage support
/*
if (processPage) {
// probably do something like what includeIntegrations does
...
}
*/
} catch (IOException ex) {
GuiUtil.getLogger().log(Level.SEVERE, "Unable to read url: " + url, ex);
}
}
// Set the content to output...
handlerCtx.setOutputValue("pluginPage", urlContents);
}
@Handler(id="getPluginIdFromViewId",
input={@HandlerInput(name="viewId",type=String.class,required=true)},
output={@HandlerOutput(name="pluginId",type=String.class)}
)
public static void getPluginIdFromViewId(HandlerContext handlerCtx) {
String viewId = (String) handlerCtx.getInputValue("viewId");
if (viewId == null) {
return;
}
ConsolePluginService cps = getPluginService(handlerCtx.getFacesContext());
String pluginId = "common";
int next = viewId.indexOf("/", 1);
if (next > -1) {
pluginId = viewId.substring(0, next);
String resource = viewId.substring(next);
if (pluginId.startsWith("/")) {
pluginId = pluginId.substring(1);
}
ClassLoader cl = cps.getModuleClassLoader(pluginId);
URL url = null;
if (cl != null) {
url = cl.getResource(resource);
}
if (url == null) {
pluginId = "common";
}
}
handlerCtx.setOutputValue("pluginId", pluginId);
}
@Handler(id="calculateHelpUrl",
input={
@HandlerInput(name="pluginId",type=String.class,required=true),
@HandlerInput(name="helpKey",type=String.class,required=true)
},
output={
@HandlerOutput(name="url",type=String.class)
}
)
public static void calculateHelpUrl(HandlerContext handlerCtx) {
String pluginId = (String) handlerCtx.getInputValue("pluginId");
String helpKey = (String)handlerCtx.getInputValue("helpKey");
ConsolePluginService cps = getPluginService(handlerCtx.getFacesContext());
ClassLoader cl = cps.getModuleClassLoader(pluginId);
// // Try the viewRoot locale first
// String path = getHelpPathForResource(helpKey, handlerCtx.getFacesContext().getViewRoot().getLocale(), cl);
// if (path == null) {
// // Try the default locale
// path = getHelpPathForResource(helpKey, Locale.getDefault(), cl);
//
// // Default to en
// if (path == null) {
// path = "/en/help/" + helpKey;
// }
// }
String path = "";
handlerCtx.setOutputValue("url", path);
}
/**
* This function attempts to calculate a help path with the
* given locale and classloader. It only succeeds if it is able to
* confirm a file exists at the generated path as determined by
* ClassLoader.getResource(path)
. The paths checked are
* the following in this order:
*
* /locale.toString()/help/<resource>
* /locale.getLanguage()_locale.getCountry()/help/<resource>
* /locale.getLanguage()/help/<resource>
*
* If all of those fail to yield a file in the classpath, then
* null
will be returned.
*/
public static String getHelpPathForResource(String resource, Locale locale, ClassLoader cl) {
String path = "/" + locale.toString() + "/help/" + resource;
// Try with full locale
boolean found = (cl.getResource(path) != null);
// Try with language_COUNTRY
if (!found) {
String language = locale.getLanguage();
String country = locale.getCountry();
path = "/" + language + "_" + country + "/help/" + resource;
found = (cl.getResource(path) != null);
// Try with just language
if (!found) {
path = "/" + language + "/help/" + resource;
found = (cl.getResource(path) != null);
if (!found) {
// Still not found, so return null
path = null;
}
}
}
return path;
}
/*
private static String getPluginIdFromViewId(ConsolePluginService cps, String viewId) {
String pluginId = "";
int next = viewId.indexOf("/", 1);
if (next > -1) {
pluginId = viewId.substring(0, next);
String resource = viewId.substring(next);
if (pluginId.startsWith("/")) {
pluginId = pluginId.substring(1);
}
ClassLoader cl = cps.getModuleClassLoader(pluginId);
if (cl != null) {
if (cl.getResource(resource) == null) {
pluginId = "";
}
}
}
return pluginId;
}
*/
}