/** * $Id: ServerConfigEntityProvider.java 130232 2013-10-08 12:32:33Z azeckoski@unicon.net $ * $URL: https://source.sakaiproject.org/svn/entitybroker/trunk/core-providers/src/java/org/sakaiproject/entitybroker/providers/ServerConfigEntityProvider.java $ * ServerConfigEntityProvider.java - entity-broker - Jul 17, 2008 2:19:03 PM - azeckoski ************************************************************************** * Copyright (c) 2008, 2009 The Sakai Foundation * * Licensed under the Educational Community License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.opensource.org/licenses/ECL-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sakaiproject.entitybroker.providers; import java.io.Serializable; import java.net.Inet4Address; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.TreeMap; import java.util.Map.Entry; import org.sakaiproject.cluster.api.ClusterService; import org.sakaiproject.component.api.ServerConfigurationService; import org.sakaiproject.entitybroker.EntityReference; import org.sakaiproject.entitybroker.EntityView; import org.sakaiproject.entitybroker.entityprovider.CoreEntityProvider; import org.sakaiproject.entitybroker.entityprovider.annotations.EntityCustomAction; import org.sakaiproject.entitybroker.entityprovider.capabilities.ActionsExecutable; import org.sakaiproject.entitybroker.entityprovider.capabilities.CollectionResolvable; import org.sakaiproject.entitybroker.entityprovider.capabilities.Describeable; import org.sakaiproject.entitybroker.entityprovider.capabilities.Outputable; import org.sakaiproject.entitybroker.entityprovider.capabilities.Resolvable; import org.sakaiproject.entitybroker.entityprovider.extension.ActionReturn; import org.sakaiproject.entitybroker.entityprovider.extension.EntityData; import org.sakaiproject.entitybroker.entityprovider.extension.Formats; import org.sakaiproject.entitybroker.entityprovider.search.Search; import org.sakaiproject.entitybroker.providers.model.EntityServerConfig; import org.sakaiproject.entitybroker.util.AbstractEntityProvider; /** * This provides access to the server configuration as entities, * output access only though, no setting of configuration * * @author Aaron Zeckoski (azeckoski @ gmail.com) */ public class ServerConfigEntityProvider extends AbstractEntityProvider implements CoreEntityProvider, Outputable, Resolvable, CollectionResolvable, ActionsExecutable, Describeable { public String[] includedStringSettings = new String[] { "portalPath", "version.service", "version.sakai", "version.kernel", "buildTime.kernel", "locales", "force.url.secure", "skin.default", "skin.repo", "ui.institution", "ui.service" }; public String[] includedBooleanSettings = new String[] { "auto.ddl", "display.users.present" }; private ServerConfigurationService serverConfigurationService; public void setServerConfigurationService(ServerConfigurationService serverConfigurationService) { this.serverConfigurationService = serverConfigurationService; } private ClusterService clusterService; public void setClusterService(ClusterService clusterService) { this.clusterService = clusterService; } public static String PREFIX = "server-config"; public String getEntityPrefix() { return PREFIX; } @EntityCustomAction(action="servers",viewKey=EntityView.VIEW_LIST) public Object getClusterServers(EntityReference ref) { List<String> servers = clusterService.getServers(); // wrapped the data in an EntityData object so it is encoded as is return new EntityData(servers); } @EntityCustomAction(action="values",viewKey=EntityView.VIEW_LIST) public Object getAllValues() { TreeMap<String, Object> tm = new TreeMap<String, Object>( getKnownSettings() ); // wrapped the data in an ActionReturn object so it is encoded as is return new ActionReturn(tm); } @EntityCustomAction(action="names",viewKey=EntityView.VIEW_LIST) public Object getAllNames(EntityReference ref) { Map<String, Object> tm = getKnownSettings(); ArrayList<String> names = new ArrayList<String>( tm.keySet() ); Collections.sort(names); // wrapped the data in an ActionReturn object so it is encoded as is return new ActionReturn(names); } /* * NOTE for anyone looking at this code, there are multiple ways to return data so that * the extra meta data is not encoded or the data is not wrapped in an entity data object, * use of the EntityData object directly is one way, the preferred way is to use the ActionReturn * since it is generally the way to handle data returns from custom actions */ public boolean entityExists(String id) { if (id == null) { return false; } if ("".equals(id)) { return true; } Object config = getConfig(id); if (config != null) { return true; } return false; } public Object getEntity(EntityReference ref) { if (ref.getId() == null) { return new EntityServerConfig(); } String name = ref.getId(); Object value = getConfig(name); if (value == null) { throw new IllegalArgumentException("Cannot find server config setting with name: " + name); } EntityServerConfig esc = makeESC(name, value); return esc; } public List<?> getEntities(EntityReference ref, Search search) { List<EntityServerConfig> escs = new ArrayList<EntityServerConfig>(); if (search != null && ! search.isEmpty() && search.getRestrictionByProperty("name") != null) { String name = (String) search.getRestrictionByProperty("name").value; Object value = getConfig(name); if (value != null) { EntityServerConfig esc = makeESC(name, value); escs.add(esc); } } else { Map<String, Object> known = getKnownSettings(); for (Entry<String, Object> entry : known.entrySet()) { String name = entry.getKey(); Object value = entry.getValue(); if (value != null) { EntityServerConfig esc = makeESC(name, value); escs.add(esc); } } } Collections.sort(escs, new ESCComparator()); return escs; } public String[] getHandledOutputFormats() { return new String[] { Formats.XML, Formats.HTML, Formats.JSON }; } public Object getConfig(String name) { Object value = null; // check in the local group of settings first Map<String, Object> known = getKnownSettings(); if (known.containsKey(name)) { value = known.get(name); } else { // now check the service is super admin (to protect sensitive settings) String currentUserRef = developerHelperService.getCurrentUserReference(); if (! developerHelperService.isUserAdmin(currentUserRef)) { throw new SecurityException("Only admins can access config properties outside of the basic set, user is not an admin: " + currentUserRef); } else { value = getConfigValue(name); } } return value; } /** * Retrieves the known values in SCS which are not actually strings and properties * @return a map of name -> value */ public Map<String, Object> getKnownSettings() { Map<String, Object> m = new HashMap<String, Object>(); m.put("accessPath", serverConfigurationService.getAccessPath()); m.put("accessUrl", serverConfigurationService.getAccessUrl()); m.put("gatewaySiteId", serverConfigurationService.getGatewaySiteId()); m.put("loggedOutUrl", serverConfigurationService.getLoggedOutUrl()); m.put("portalUrl", serverConfigurationService.getPortalUrl()); //m.put("sakaiHomePath", serverConfigurationService.getSakaiHomePath()); // SAK-23142 m.put("serverId", serverConfigurationService.getServerId()); m.put("serverIdInstance", serverConfigurationService.getServerIdInstance()); m.put("serverInstance", serverConfigurationService.getServerInstance()); m.put("serverName", serverConfigurationService.getServerName()); m.put("serverUrl", serverConfigurationService.getServerUrl()); m.put("toolUrl", serverConfigurationService.getToolUrl()); m.put("userHomeUrl", serverConfigurationService.getUserHomeUrl()); // added in server IP address and hostname try { InetAddress i4 = Inet4Address.getLocalHost(); m.put("serverHostName", i4.getHostName()); m.put("serverHostAddress", i4.getHostAddress()); // IP address } catch (UnknownHostException e) { // could not get address, do nothing? } // special handling for DB properties Object o = getConfigValue("vendor@org.sakaiproject.db.api.SqlService"); if (o != null) m.put("database.vendor", o); o = getConfigValue("webdav.ignore"); if (o != null) m.put("webdav.ignore", o); // now we get the known String settings for (int i = 0; i < includedStringSettings.length; i++) { String name = includedStringSettings[i]; String value = serverConfigurationService.getString(name); if (value != null) { m.put(name, value); } } // now get the known boolean settings for (int i = 0; i < includedBooleanSettings.length; i++) { String name = includedBooleanSettings[i]; boolean value = serverConfigurationService.getBoolean(name, false); m.put(name, value); } return m; } public static class ESCComparator implements Comparator<EntityServerConfig>, Serializable { public final static long serialVersionUID = 1l; public int compare(EntityServerConfig o1, EntityServerConfig o2) { return o1.getName().compareTo(o2.getName()); } } /** * Internal method to get a value from the SCS directly * @param name the config name * @return the value of null if none found */ private Object getConfigValue(String name) { Object value = serverConfigurationService.getString(name); if (value == null || "".equals(value)) { // oddly this returns empty string if the item is an array // could not find it so get the array instead String[] array = serverConfigurationService.getStrings(name); if (array != null && array.length > 0) { value = array; } } else { String sValue = (String) value; if (sValue.length() > 0) { // try to convert this to an integer first try { Integer i = Integer.parseInt(sValue); value = i.intValue(); } catch (NumberFormatException e) { // next try to convert it to a boolean if (sValue.equalsIgnoreCase("true")) { value = true; } else if (sValue.equalsIgnoreCase("false")) { value = false; } } // otherwise leave it as a string } } return value; } /** * Internal method to determine a printable type * @param value any object * @return a string representing the type (readable) */ private String getConfigType(Object value) { String type = "null"; if (value != null) { Class<?> c = value.getClass(); if (String.class.equals(c)) { type = "string"; } else if (Integer.class.equals(c)) { type = "int"; } else if (Boolean.class.equals(c)) { type = "boolean"; } else if (c.isArray()) { StringBuilder sb = new StringBuilder("array("); if (String.class.equals(c.getComponentType())) { sb.append("string"); } else if (Integer.class.equals(c.getComponentType())) { sb.append("int"); } else if (Boolean.class.equals(c.getComponentType())) { sb.append("boolean"); } else { sb.append(c.getName()); } sb.append(")"); type = sb.toString(); } else { type = c.getName(); } } return type; } /** * Construct an entity object from name and value * @param name * @param value * @return an ESC entity */ private EntityServerConfig makeESC(String name, Object value) { return new EntityServerConfig(name, value, getConfigType(value)); } }