diff options
author | Teemu Suo-Anttila <teemusa@vaadin.com> | 2016-03-10 22:40:51 +0200 |
---|---|---|
committer | Teemu Suo-Anttila <teemusa@vaadin.com> | 2016-03-14 07:59:12 +0200 |
commit | a6653d3fe49e6a97468ac09f7f2f4d621bea1078 (patch) | |
tree | 96c82e20ca6551ee4c14c8877f0258b25c63cddf /server/src/main/java/com/vaadin/util | |
parent | f7e57d77ce621ee39167369c31d989edc5633266 (diff) | |
download | vaadin-framework-a6653d3fe49e6a97468ac09f7f2f4d621bea1078.tar.gz vaadin-framework-a6653d3fe49e6a97468ac09f7f2f4d621bea1078.zip |
Migrate vaadin-server build to maven
Change-Id: I5c740f4e9cb28103bab199f9a552153d82277e7e
Diffstat (limited to 'server/src/main/java/com/vaadin/util')
5 files changed, 1224 insertions, 0 deletions
diff --git a/server/src/main/java/com/vaadin/util/ConnectorHelper.java b/server/src/main/java/com/vaadin/util/ConnectorHelper.java new file mode 100644 index 0000000000..b3457068c3 --- /dev/null +++ b/server/src/main/java/com/vaadin/util/ConnectorHelper.java @@ -0,0 +1,101 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache 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.apache.org/licenses/LICENSE-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 com.vaadin.util; + +import java.util.LinkedList; + +import com.vaadin.server.ClientConnector; +import com.vaadin.ui.Component; + +/** + * Provides various helper methods for connectors. Meant for internal use. + * + * @since 7.1 + * @author Vaadin Ltd + */ +public class ConnectorHelper { + + /** + * Creates a string containing debug info for the connector + * + * @since 7.1 + * @param connector + * The connector to print debug info about + * @return A string with debug information + */ + public static String getDebugInformation(ClientConnector connector) { + StringBuilder sb = new StringBuilder(); + sb.append("*** Debug details of a connector: *** \n"); + sb.append("Type: "); + sb.append(connector.getClass().getName()); + sb.append("\nId:"); + sb.append(connector.getConnectorId()); + if (connector instanceof Component) { + Component component = (Component) connector; + if (component.getCaption() != null) { + sb.append("\nCaption:"); + sb.append(component.getCaption()); + } + } + writeHierarchyInformation(connector, sb); + return sb.toString(); + } + + /** + * Creates a string containing hierarchy information for the connector + * + * @since 7.1 + * @param connector + * The connector to get hierarchy information for + * @param builder + * The StringBuilder where the information should be written + */ + public static void writeHierarchyInformation(ClientConnector connector, + StringBuilder builder) { + LinkedList<ClientConnector> h = new LinkedList<ClientConnector>(); + h.add(connector); + ClientConnector parent = connector.getParent(); + while (parent != null) { + h.addFirst(parent); + parent = parent.getParent(); + } + + builder.append("\nConnector hierarchy:\n"); + + int l = 0; + for (ClientConnector connector2 : h) { + if (l != 0) { + builder.append("\n"); + for (int i = 0; i < l; i++) { + builder.append(" "); + } + } + l++; + Class<? extends ClientConnector> connectorClass = connector2 + .getClass(); + Class<?> topClass = connectorClass; + while (topClass.getEnclosingClass() != null) { + topClass = topClass.getEnclosingClass(); + } + builder.append(connectorClass.getName()); + builder.append("("); + builder.append(topClass.getSimpleName()); + builder.append(".java:1)"); + } + } + +} diff --git a/server/src/main/java/com/vaadin/util/CurrentInstance.java b/server/src/main/java/com/vaadin/util/CurrentInstance.java new file mode 100644 index 0000000000..e6b58ec65c --- /dev/null +++ b/server/src/main/java/com/vaadin/util/CurrentInstance.java @@ -0,0 +1,355 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache 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.apache.org/licenses/LICENSE-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 com.vaadin.util; + +import java.io.Serializable; +import java.lang.ref.WeakReference; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.server.VaadinResponse; +import com.vaadin.server.VaadinService; +import com.vaadin.server.VaadinSession; +import com.vaadin.ui.UI; + +/** + * Keeps track of various current instances for the current thread. All the + * instances are automatically cleared after handling a request from the client + * to avoid leaking memory. The inheritable values are also maintained when + * execution is moved to another thread, both when a new thread is created and + * when {@link VaadinSession#access(Runnable)} or {@link UI#access(Runnable)} is + * used. + * <p> + * Please note that the instances are stored using {@link WeakReference}. This + * means that the a current instance value may suddenly disappear if there a no + * other references to the object. + * <p> + * Currently the framework uses the following instances: + * </p> + * <p> + * Inheritable: {@link UI}, {@link VaadinService}, {@link VaadinSession}. + * </p> + * <p> + * Non-inheritable: {@link VaadinRequest}, {@link VaadinResponse}. + * </p> + * + * @author Vaadin Ltd + * @since 7.0.0 + */ +public class CurrentInstance implements Serializable { + private static final Object NULL_OBJECT = new Object(); + private static final CurrentInstance CURRENT_INSTANCE_NULL = new CurrentInstance( + NULL_OBJECT, true); + + private final WeakReference<Object> instance; + private final boolean inheritable; + + private static InheritableThreadLocal<Map<Class<?>, CurrentInstance>> instances = new InheritableThreadLocal<Map<Class<?>, CurrentInstance>>() { + @Override + protected Map<Class<?>, CurrentInstance> childValue( + Map<Class<?>, CurrentInstance> parentValue) { + if (parentValue == null) { + return null; + } + + Map<Class<?>, CurrentInstance> value = new HashMap<Class<?>, CurrentInstance>(); + + // Copy all inheritable values to child map + for (Entry<Class<?>, CurrentInstance> e : parentValue.entrySet()) { + if (e.getValue().inheritable) { + value.put(e.getKey(), e.getValue()); + } + } + + return value; + } + }; + + private CurrentInstance(Object instance, boolean inheritable) { + this.instance = new WeakReference<Object>(instance); + this.inheritable = inheritable; + } + + /** + * Gets the current instance of a specific type if available. + * + * @param type + * the class to get an instance of + * @return the current instance or the provided type, or <code>null</code> + * if there is no current instance. + */ + public static <T> T get(Class<T> type) { + Map<Class<?>, CurrentInstance> map = instances.get(); + if (map == null) { + return null; + } + CurrentInstance currentInstance = map.get(type); + if (currentInstance != null) { + Object value = currentInstance.instance.get(); + if (value == null) { + /* + * This is believed to never actually happen since the + * ThreadLocal should only outlive the referenced object on + * threads that are not doing anything related to Vaadin, which + * should thus never invoke CurrentInstance.get(). + * + * At this point, there might also be other values that have + * been collected, so we'll scan the entire map and remove stale + * CurrentInstance objects. Using a ReferenceQueue could make + * this assumingly rare case slightly more efficient, but would + * significantly increase the complexity of the code for + * maintaining a separate ReferenceQueue for each Thread. + */ + removeStaleInstances(map); + + if (map.isEmpty()) { + instances.remove(); + } + + return null; + } + return type.cast(value); + } else { + return null; + } + } + + private static void removeStaleInstances(Map<Class<?>, CurrentInstance> map) { + for (Iterator<Entry<Class<?>, CurrentInstance>> iterator = map + .entrySet().iterator(); iterator.hasNext();) { + Entry<Class<?>, CurrentInstance> entry = iterator.next(); + Object instance = entry.getValue().instance.get(); + if (instance == null) { + iterator.remove(); + getLogger().log(Level.FINE, + "CurrentInstance for {0} has been garbage collected.", + entry.getKey()); + } + } + } + + /** + * Sets the current instance of the given type. + * + * @see #setInheritable(Class, Object) + * @see ThreadLocal + * + * @param type + * the class that should be used when getting the current + * instance back + * @param instance + * the actual instance + */ + public static <T> void set(Class<T> type, T instance) { + set(type, instance, false); + } + + /** + * Sets the current inheritable instance of the given type. A current + * instance that is inheritable will be available for child threads and in + * code run by {@link VaadinSession#access(Runnable)} and + * {@link UI#access(Runnable)}. + * + * @see #set(Class, Object) + * @see InheritableThreadLocal + * + * @param type + * the class that should be used when getting the current + * instance back + * @param instance + * the actual instance + */ + public static <T> void setInheritable(Class<T> type, T instance) { + set(type, instance, true); + } + + private static <T> CurrentInstance set(Class<T> type, T instance, + boolean inheritable) { + Map<Class<?>, CurrentInstance> map = instances.get(); + CurrentInstance previousInstance = null; + if (instance == null) { + // remove the instance + if (map != null) { + previousInstance = map.remove(type); + if (map.isEmpty()) { + instances.remove(); + map = null; + } + } + } else { + assert type.isInstance(instance) : "Invald instance type"; + if (map == null) { + map = new HashMap<Class<?>, CurrentInstance>(); + instances.set(map); + } + + previousInstance = map.put(type, new CurrentInstance(instance, + inheritable)); + if (previousInstance != null) { + assert previousInstance.inheritable == inheritable : "Inheritable status mismatch for " + + type + + " (previous was " + + previousInstance.inheritable + + ", new is " + + inheritable + ")"; + } + } + if (previousInstance == null) { + previousInstance = CURRENT_INSTANCE_NULL; + } + return previousInstance; + } + + /** + * Clears all current instances. + */ + public static void clearAll() { + instances.remove(); + } + + /** + * Restores the given instances to the given values. Note that this should + * only be used internally to restore Vaadin classes. + * + * @since 7.1 + * + * @param old + * A Class -> CurrentInstance map to set as current instances + */ + public static void restoreInstances(Map<Class<?>, CurrentInstance> old) { + boolean removeStale = false; + for (Class c : old.keySet()) { + CurrentInstance ci = old.get(c); + Object v = ci.instance.get(); + if (v == null) { + removeStale = true; + } else if (v == NULL_OBJECT) { + /* + * NULL_OBJECT is used to identify objects that are null when + * #setCurrent(UI) or #setCurrent(VaadinSession) are called on a + * CurrentInstance. Without this a reference to an already + * collected instance may be left in the CurrentInstance when it + * really should be restored to null. + * + * One example case that this fixes: + * VaadinService.runPendingAccessTasks() clears all current + * instances and then sets everything but the UI. This makes + * UI.accessSynchronously() save these values before calling + * setCurrent(UI), which stores UI=null in the map it returns. + * This map will be restored after UI.accessSync(), which, + * unless it respects null values, will just leave the wrong UI + * instance registered. + */ + v = null; + } + set(c, v, ci.inheritable); + } + + if (removeStale) { + removeStaleInstances(old); + } + } + + /** + * Gets the currently set instances so that they can later be restored using + * {@link #restoreInstances(Map)}. + * + * @since 7.1 + * + * @param onlyInheritable + * <code>true</code> if only the inheritable instances should be + * included; <code>false</code> to get all instances. + * @return a map containing the current instances + */ + public static Map<Class<?>, CurrentInstance> getInstances( + boolean onlyInheritable) { + Map<Class<?>, CurrentInstance> map = instances.get(); + if (map == null) { + return Collections.emptyMap(); + } else { + Map<Class<?>, CurrentInstance> copy = new HashMap<Class<?>, CurrentInstance>(); + boolean removeStale = false; + for (Class<?> c : map.keySet()) { + CurrentInstance ci = map.get(c); + if (ci.instance.get() == null) { + removeStale = true; + } else if (ci.inheritable || !onlyInheritable) { + copy.put(c, ci); + } + } + if (removeStale) { + removeStaleInstances(map); + if (map.isEmpty()) { + instances.remove(); + } + } + return copy; + } + } + + /** + * Sets current instances for the UI and all related classes. The previously + * defined values can be restored by passing the returned map to + * {@link #restoreInstances(Map)}. + * + * @since 7.1 + * + * @param ui + * The UI + * @return A map containing the old values of the instances that this method + * updated. + */ + public static Map<Class<?>, CurrentInstance> setCurrent(UI ui) { + Map<Class<?>, CurrentInstance> old = setCurrent(ui.getSession()); + old.put(UI.class, set(UI.class, ui, true)); + return old; + } + + /** + * Sets current instances for the {@link VaadinSession} and all related + * classes. The previously defined values can be restored by passing the + * returned map to {@link #restoreInstances(Map)}. + * + * @since 7.1 + * + * @param session + * The VaadinSession + * @return A map containing the old values of the instances this method + * updated. + */ + public static Map<Class<?>, CurrentInstance> setCurrent( + VaadinSession session) { + Map<Class<?>, CurrentInstance> old = new HashMap<Class<?>, CurrentInstance>(); + old.put(VaadinSession.class, set(VaadinSession.class, session, true)); + VaadinService service = null; + if (session != null) { + service = session.getService(); + } + old.put(VaadinService.class, set(VaadinService.class, service, true)); + return old; + } + + private static Logger getLogger() { + return Logger.getLogger(CurrentInstance.class.getName()); + } +} diff --git a/server/src/main/java/com/vaadin/util/FileTypeResolver.java b/server/src/main/java/com/vaadin/util/FileTypeResolver.java new file mode 100644 index 0000000000..a49a0e2d01 --- /dev/null +++ b/server/src/main/java/com/vaadin/util/FileTypeResolver.java @@ -0,0 +1,395 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache 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.apache.org/licenses/LICENSE-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 com.vaadin.util; + +import java.io.File; +import java.io.Serializable; +import java.util.Collections; +import java.util.Hashtable; +import java.util.Map; +import java.util.StringTokenizer; + +import com.vaadin.server.Resource; +import com.vaadin.server.ThemeResource; + +/** + * Utility class that can figure out mime-types and icons related to files. + * <p> + * Note : The icons are associated purely to mime-types, so a file may not have + * a custom icon accessible with this class. + * </p> + * + * @author Vaadin Ltd. + * @since 3.0 + */ +@SuppressWarnings("serial") +public class FileTypeResolver implements Serializable { + + /** + * Default icon given if no icon is specified for a mime-type. + */ + static public Resource DEFAULT_ICON = new ThemeResource( + "../runo/icons/16/document.png"); + + /** + * Default mime-type. + */ + static public String DEFAULT_MIME_TYPE = "application/octet-stream"; + + /** + * Initial file extension to mime-type mapping. + */ + static private String initialExtToMIMEMap = "application/cu-seeme csm cu," + + "application/dsptype tsp," + + "application/futuresplash spl," + + "application/mac-binhex40 hqx," + + "application/msaccess mdb," + + "application/msword doc dot," + + "application/octet-stream bin," + + "application/oda oda," + + "application/pdf pdf," + + "application/pgp-signature pgp," + + "application/postscript ps ai eps," + + "application/rtf rtf," + + "application/vnd.ms-excel xls xlb," + + "application/vnd.ms-powerpoint ppt pps pot," + + "application/vnd.wap.wmlc wmlc," + + "application/vnd.wap.wmlscriptc wmlsc," + + "application/wordperfect5.1 wp5," + + "application/zip zip," + + "application/x-123 wk," + + "application/x-bcpio bcpio," + + "application/x-chess-pgn pgn," + + "application/x-cpio cpio," + + "application/x-debian-package deb," + + "application/x-director dcr dir dxr," + + "application/x-dms dms," + + "application/x-dvi dvi," + + "application/x-xfig fig," + + "application/x-font pfa pfb gsf pcf pcf.Z," + + "application/x-gnumeric gnumeric," + + "application/x-gtar gtar tgz taz," + + "application/x-hdf hdf," + + "application/x-httpd-php phtml pht php," + + "application/x-httpd-php3 php3," + + "application/x-httpd-php3-source phps," + + "application/x-httpd-php3-preprocessed php3p," + + "application/x-httpd-php4 php4," + + "application/x-ica ica," + + "application/x-java-archive jar," + + "application/x-java-serialized-object ser," + + "application/x-java-vm class," + + "application/x-javascript js," + + "application/x-kchart chrt," + + "application/x-killustrator kil," + + "application/x-kpresenter kpr kpt," + + "application/x-kspread ksp," + + "application/x-kword kwd kwt," + + "application/x-latex latex," + + "application/x-lha lha," + + "application/x-lzh lzh," + + "application/x-lzx lzx," + + "application/x-maker frm maker frame fm fb book fbdoc," + + "application/x-mif mif," + + "application/x-msdos-program com exe bat dll," + + "application/x-msi msi," + + "application/x-netcdf nc cdf," + + "application/x-ns-proxy-autoconfig pac," + + "application/x-object o," + + "application/x-ogg ogg," + + "application/x-oz-application oza," + + "application/x-perl pl pm," + + "application/x-pkcs7-crl crl," + + "application/x-redhat-package-manager rpm," + + "application/x-shar shar," + + "application/x-shockwave-flash swf swfl," + + "application/x-star-office sdd sda," + + "application/x-stuffit sit," + + "application/x-sv4cpio sv4cpio," + + "application/x-sv4crc sv4crc," + + "application/x-tar tar," + + "application/x-tex-gf gf," + + "application/x-tex-pk pk PK," + + "application/x-texinfo texinfo texi," + + "application/x-trash ~ % bak old sik," + + "application/x-troff t tr roff," + + "application/x-troff-man man," + + "application/x-troff-me me," + + "application/x-troff-ms ms," + + "application/x-ustar ustar," + + "application/x-wais-source src," + + "application/x-wingz wz," + + "application/x-x509-ca-cert crt," + + "audio/basic au snd," + + "audio/midi mid midi," + + "audio/mpeg mpga mpega mp2 mp3," + + "audio/mpegurl m3u," + + "audio/prs.sid sid," + + "audio/x-aiff aif aiff aifc," + + "audio/x-gsm gsm," + + "audio/x-pn-realaudio ra rm ram," + + "audio/x-scpls pls," + + "audio/x-wav wav," + + "audio/ogg ogg," + + "audio/mp4 m4a," + + "audio/x-aac aac," + + "image/bitmap bmp," + + "image/gif gif," + + "image/ief ief," + + "image/jpeg jpeg jpg jpe," + + "image/pcx pcx," + + "image/png png," + + "image/svg+xml svg svgz," + + "image/tiff tiff tif," + + "image/vnd.wap.wbmp wbmp," + + "image/x-cmu-raster ras," + + "image/x-coreldraw cdr," + + "image/x-coreldrawpattern pat," + + "image/x-coreldrawtemplate cdt," + + "image/x-corelphotopaint cpt," + + "image/x-jng jng," + + "image/x-portable-anymap pnm," + + "image/x-portable-bitmap pbm," + + "image/x-portable-graymap pgm," + + "image/x-portable-pixmap ppm," + + "image/x-rgb rgb," + + "image/x-xbitmap xbm," + + "image/x-xpixmap xpm," + + "image/x-xwindowdump xwd," + + "text/comma-separated-values csv," + + "text/css css," + + "text/html htm html xhtml," + + "text/mathml mml," + + "text/plain txt text diff," + + "text/richtext rtx," + + "text/tab-separated-values tsv," + + "text/vnd.wap.wml wml," + + "text/vnd.wap.wmlscript wmls," + + "text/xml xml," + + "text/x-c++hdr h++ hpp hxx hh," + + "text/x-c++src c++ cpp cxx cc," + + "text/x-chdr h," + + "text/x-csh csh," + + "text/x-csrc c," + + "text/x-java java," + + "text/x-moc moc," + + "text/x-pascal p pas," + + "text/x-setext etx," + + "text/x-sh sh," + + "text/x-tcl tcl tk," + + "text/x-tex tex ltx sty cls," + + "text/x-vcalendar vcs," + + "text/x-vcard vcf," + + "video/dl dl," + + "video/fli fli," + + "video/gl gl," + + "video/mpeg mpeg mpg mpe," + + "video/quicktime qt mov," + + "video/x-mng mng," + + "video/x-ms-asf asf asx," + + "video/x-msvideo avi," + + "video/x-sgi-movie movie," + + "video/ogg ogv," + + "video/mp4 mp4," + + "x-world/x-vrml vrm vrml wrl"; + + /** + * File extension to MIME type mapping. All extensions are in lower case. + */ + static private Hashtable<String, String> extToMIMEMap = new Hashtable<String, String>(); + + /** + * MIME type to Icon mapping. + */ + static private Hashtable<String, Resource> MIMEToIconMap = new Hashtable<String, Resource>(); + + static { + + // Initialize extension to MIME map + final StringTokenizer lines = new StringTokenizer(initialExtToMIMEMap, + ","); + while (lines.hasMoreTokens()) { + final String line = lines.nextToken(); + final StringTokenizer exts = new StringTokenizer(line); + final String type = exts.nextToken(); + while (exts.hasMoreTokens()) { + final String ext = exts.nextToken(); + addExtension(ext, type); + } + } + + // Initialize Icons + ThemeResource folder = new ThemeResource("../runo/icons/16/folder.png"); + addIcon("inode/drive", folder); + addIcon("inode/directory", folder); + } + + /** + * Gets the mime-type of a file. Currently the mime-type is resolved based + * only on the file name extension. + * + * @param fileName + * the name of the file whose mime-type is requested. + * @return mime-type <code>String</code> for the given filename + */ + public static String getMIMEType(String fileName) { + + // Checks for nulls + if (fileName == null) { + throw new NullPointerException("Filename can not be null"); + } + + // Calculates the extension of the file + int dotIndex = fileName.indexOf("."); + while (dotIndex >= 0 && fileName.indexOf(".", dotIndex + 1) >= 0) { + dotIndex = fileName.indexOf(".", dotIndex + 1); + } + dotIndex++; + + if (fileName.length() > dotIndex) { + String ext = fileName.substring(dotIndex); + + // Ignore any query parameters + int queryStringStart = ext.indexOf('?'); + if (queryStringStart > 0) { + ext = ext.substring(0, queryStringStart); + } + + // Return type from extension map, if found + final String type = extToMIMEMap.get(ext.toLowerCase()); + if (type != null) { + return type; + } + } + + return DEFAULT_MIME_TYPE; + } + + /** + * Gets the descriptive icon representing file, based on the filename. First + * the mime-type for the given filename is resolved, and then the + * corresponding icon is fetched from the internal icon storage. If it is + * not found the default icon is returned. + * + * @param fileName + * the name of the file whose icon is requested. + * @return the icon corresponding to the given file + */ + public static Resource getIcon(String fileName) { + return getIconByMimeType(getMIMEType(fileName)); + } + + private static Resource getIconByMimeType(String mimeType) { + final Resource icon = MIMEToIconMap.get(mimeType); + if (icon != null) { + return icon; + } + + // If nothing is known about the file-type, general file + // icon is used + return DEFAULT_ICON; + } + + /** + * Gets the descriptive icon representing a file. First the mime-type for + * the given file name is resolved, and then the corresponding icon is + * fetched from the internal icon storage. If it is not found the default + * icon is returned. + * + * @param file + * the file whose icon is requested. + * @return the icon corresponding to the given file + */ + public static Resource getIcon(File file) { + return getIconByMimeType(getMIMEType(file)); + } + + /** + * Gets the mime-type for a file. Currently the returned file type is + * resolved by the filename extension only. + * + * @param file + * the file whose mime-type is requested. + * @return the files mime-type <code>String</code> + */ + public static String getMIMEType(File file) { + + // Checks for nulls + if (file == null) { + throw new NullPointerException("File can not be null"); + } + + // Directories + if (file.isDirectory()) { + // Drives + if (file.getParentFile() == null) { + return "inode/drive"; + } else { + return "inode/directory"; + } + } + + // Return type from extension + return getMIMEType(file.getName()); + } + + /** + * Adds a mime-type mapping for the given filename extension. If the + * extension is already in the internal mapping it is overwritten. + * + * @param extension + * the filename extension to be associated with + * <code>MIMEType</code>. + * @param MIMEType + * the new mime-type for <code>extension</code>. + */ + public static void addExtension(String extension, String MIMEType) { + extToMIMEMap.put(extension.toLowerCase(), MIMEType); + } + + /** + * Adds a icon for the given mime-type. If the mime-type also has a + * corresponding icon, it is replaced with the new icon. + * + * @param MIMEType + * the mime-type whose icon is to be changed. + * @param icon + * the new icon to be associated with <code>MIMEType</code>. + */ + public static void addIcon(String MIMEType, Resource icon) { + MIMEToIconMap.put(MIMEType, icon); + } + + /** + * Gets the internal file extension to mime-type mapping. + * + * @return unmodifiable map containing the current file extension to + * mime-type mapping + */ + public static Map<String, String> getExtensionToMIMETypeMapping() { + return Collections.unmodifiableMap(extToMIMEMap); + } + + /** + * Gets the internal mime-type to icon mapping. + * + * @return unmodifiable map containing the current mime-type to icon mapping + */ + public static Map<String, Resource> getMIMETypeToIconMapping() { + return Collections.unmodifiableMap(MIMEToIconMap); + } +} diff --git a/server/src/main/java/com/vaadin/util/ReflectTools.java b/server/src/main/java/com/vaadin/util/ReflectTools.java new file mode 100644 index 0000000000..2e2d3fe238 --- /dev/null +++ b/server/src/main/java/com/vaadin/util/ReflectTools.java @@ -0,0 +1,216 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache 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.apache.org/licenses/LICENSE-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 com.vaadin.util; + +import java.beans.IntrospectionException; +import java.beans.PropertyDescriptor; +import java.io.Serializable; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/** + * An util class with helpers for reflection operations. Used internally by + * Vaadin and should not be used by application developers. Subject to change at + * any time. + * + * @since 6.2 + */ +public class ReflectTools implements Serializable { + /** + * Locates the method in the given class. Returns null if the method is not + * found. Throws an ExceptionInInitializerError if there is a problem + * locating the method as this is mainly called from static blocks. + * + * @param cls + * Class that contains the method + * @param methodName + * The name of the method + * @param parameterTypes + * The parameter types for the method. + * @return A reference to the method + * @throws ExceptionInInitializerError + * Wraps any exception in an {@link ExceptionInInitializerError} + * so this method can be called from a static initializer. + */ + public static Method findMethod(Class<?> cls, String methodName, + Class<?>... parameterTypes) throws ExceptionInInitializerError { + try { + return cls.getDeclaredMethod(methodName, parameterTypes); + } catch (Exception e) { + throw new ExceptionInInitializerError(e); + } + } + + /** + * Returns the value of the java field. + * <p> + * Uses getter if present, otherwise tries to access even private fields + * directly. + * + * @param object + * The object containing the field + * @param field + * The field we want to get the value for + * @return The value of the field in the object + * @throws InvocationTargetException + * If the value could not be retrieved + * @throws IllegalAccessException + * If the value could not be retrieved + * @throws IllegalArgumentException + * If the value could not be retrieved + */ + public static Object getJavaFieldValue(Object object, + java.lang.reflect.Field field) throws IllegalArgumentException, + IllegalAccessException, InvocationTargetException { + PropertyDescriptor pd; + try { + pd = new PropertyDescriptor(field.getName(), object.getClass()); + Method getter = pd.getReadMethod(); + if (getter != null) { + return getter.invoke(object, (Object[]) null); + } + } catch (IntrospectionException e1) { + // Ignore this and try to get directly using the field + } + + // Try to get the value or throw an exception + if (!field.isAccessible()) { + // Try to gain access even if field is private + field.setAccessible(true); + } + return field.get(object); + } + + /** + * Returns the value of the java field that is assignable to the property + * type. + * <p> + * Uses getter if a getter for the correct return type is present, otherwise + * tries to access even private fields directly. If the java field is not + * assignable to the property type throws an IllegalArgumentException. + * + * @param object + * The object containing the field + * @param field + * The field we want to get the value for + * @param propertyType + * The type the field must be assignable to + * @return The value of the field in the object + * @throws InvocationTargetException + * If the value could not be retrieved + * @throws IllegalAccessException + * If the value could not be retrieved + * @throws IllegalArgumentException + * If the value could not be retrieved + */ + public static Object getJavaFieldValue(Object object, + java.lang.reflect.Field field, Class<?> propertyType) + throws IllegalArgumentException, IllegalAccessException, + InvocationTargetException { + PropertyDescriptor pd; + try { + pd = new PropertyDescriptor(field.getName(), object.getClass()); + if (propertyType.isAssignableFrom(pd.getPropertyType())) { + Method getter = pd.getReadMethod(); + if (getter != null) { + return getter.invoke(object, (Object[]) null); + } + } + } catch (IntrospectionException e1) { + // Ignore this and try to get directly using the field + } + // If the field's type cannot be casted in to the requested type + if (!propertyType.isAssignableFrom(field.getType())) { + throw new IllegalArgumentException(); + } + // Try to get the value or throw an exception + if (!field.isAccessible()) { + // Try to gain access even if field is private + field.setAccessible(true); + } + return field.get(object); + } + + /** + * Sets the value of a java field. + * <p> + * Uses setter if present, otherwise tries to access even private fields + * directly. + * + * @param object + * The object containing the field + * @param field + * The field we want to set the value for + * @param value + * The value to set + * @throws IllegalAccessException + * If the value could not be assigned to the field + * @throws IllegalArgumentException + * If the value could not be assigned to the field + * @throws InvocationTargetException + * If the value could not be assigned to the field + */ + public static void setJavaFieldValue(Object object, + java.lang.reflect.Field field, Object value) + throws IllegalAccessException, IllegalArgumentException, + InvocationTargetException { + PropertyDescriptor pd; + try { + pd = new PropertyDescriptor(field.getName(), object.getClass()); + Method setter = pd.getWriteMethod(); + if (setter != null) { + // Exceptions are thrown forward if this fails + setter.invoke(object, value); + } + } catch (IntrospectionException e1) { + // Ignore this and try to set directly using the field + } + + // Try to set the value directly to the field or throw an exception + if (!field.isAccessible()) { + // Try to gain access even if field is private + field.setAccessible(true); + } + field.set(object, value); + } + + /** + * @since 7.4 + */ + public static Class<?> convertPrimitiveType(Class<?> type) { + // Gets the return type from get method + if (type.isPrimitive()) { + if (type.equals(Boolean.TYPE)) { + type = Boolean.class; + } else if (type.equals(Integer.TYPE)) { + type = Integer.class; + } else if (type.equals(Float.TYPE)) { + type = Float.class; + } else if (type.equals(Double.TYPE)) { + type = Double.class; + } else if (type.equals(Byte.TYPE)) { + type = Byte.class; + } else if (type.equals(Character.TYPE)) { + type = Character.class; + } else if (type.equals(Short.TYPE)) { + type = Short.class; + } else if (type.equals(Long.TYPE)) { + type = Long.class; + } + } + return type; + } +} diff --git a/server/src/main/java/com/vaadin/util/SerializerHelper.java b/server/src/main/java/com/vaadin/util/SerializerHelper.java new file mode 100644 index 0000000000..793488d892 --- /dev/null +++ b/server/src/main/java/com/vaadin/util/SerializerHelper.java @@ -0,0 +1,157 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache 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.apache.org/licenses/LICENSE-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 com.vaadin.util; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +/** + * Helper class for performing serialization. Most of the methods are here are + * workarounds for problems in Google App Engine. Used internally by Vaadin and + * should not be used by application developers. Subject to change at any time. + * + * @since 6.0 + */ +public class SerializerHelper { + + /** + * Serializes the class reference so {@link #readClass(ObjectInputStream)} + * can deserialize it. Supports null class references. + * + * @param out + * The {@link ObjectOutputStream} to serialize to. + * @param cls + * A class or null. + * @throws IOException + * Rethrows any IOExceptions from the ObjectOutputStream + */ + public static void writeClass(ObjectOutputStream out, Class<?> cls) + throws IOException { + if (cls == null) { + out.writeObject(null); + } else { + out.writeObject(cls.getName()); + } + + } + + /** + * Serializes the class references so + * {@link #readClassArray(ObjectInputStream)} can deserialize it. Supports + * null class arrays. + * + * @param out + * The {@link ObjectOutputStream} to serialize to. + * @param classes + * An array containing class references or null. + * @throws IOException + * Rethrows any IOExceptions from the ObjectOutputStream + */ + public static void writeClassArray(ObjectOutputStream out, + Class<?>[] classes) throws IOException { + if (classes == null) { + out.writeObject(null); + } else { + String[] classNames = new String[classes.length]; + for (int i = 0; i < classes.length; i++) { + classNames[i] = classes[i].getName(); + } + out.writeObject(classNames); + } + } + + /** + * Deserializes a class references serialized by + * {@link #writeClassArray(ObjectOutputStream, Class[])}. Supports null + * class arrays. + * + * @param in + * {@link ObjectInputStream} to read from. + * @return Class array with the class references or null. + * @throws ClassNotFoundException + * If one of the classes could not be resolved. + * @throws IOException + * Rethrows IOExceptions from the ObjectInputStream + */ + public static Class<?>[] readClassArray(ObjectInputStream in) + throws ClassNotFoundException, IOException { + String[] classNames = (String[]) in.readObject(); + if (classNames == null) { + return null; + } + Class<?>[] classes = new Class<?>[classNames.length]; + for (int i = 0; i < classNames.length; i++) { + classes[i] = resolveClass(classNames[i]); + } + + return classes; + } + + /** + * List of primitive classes. Google App Engine has problems + * serializing/deserializing these (#3064). + */ + private static Class<?>[] primitiveClasses = new Class<?>[] { byte.class, + short.class, int.class, long.class, float.class, double.class, + boolean.class, char.class }; + + /** + * Resolves the class given by {@code className}. + * + * @param className + * The fully qualified class name. + * @return A {@code Class} reference. + * @throws ClassNotFoundException + * If the class could not be resolved. + */ + public static Class<?> resolveClass(String className) + throws ClassNotFoundException { + for (Class<?> c : primitiveClasses) { + if (className.equals(c.getName())) { + return c; + } + } + + return Class.forName(className); + } + + /** + * Deserializes a class reference serialized by + * {@link #writeClass(ObjectOutputStream, Class)}. Supports null class + * references. + * + * @param in + * {@code ObjectInputStream} to read from. + * @return Class reference to the resolved class + * @throws ClassNotFoundException + * If the class could not be resolved. + * @throws IOException + * Rethrows IOExceptions from the ObjectInputStream + */ + public static Class<?> readClass(ObjectInputStream in) throws IOException, + ClassNotFoundException { + String className = (String) in.readObject(); + if (className == null) { + return null; + } else { + return resolveClass(className); + + } + + } + +} |