/* * Copyright 2000-2016 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.ui; import java.io.Serializable; import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.List; import com.vaadin.annotations.HtmlImport; import com.vaadin.annotations.JavaScript; import com.vaadin.annotations.StyleSheet; import com.vaadin.server.ClientConnector; import com.vaadin.server.DependencyFilter; import com.vaadin.server.DependencyFilter.FilterContext; import com.vaadin.server.LegacyCommunicationManager; import com.vaadin.server.VaadinService; /** * Represents a stylesheet or JavaScript to include on the page. * * @author Vaadin Ltd * @since 8.0 */ public class Dependency implements Serializable { /** * The type of dependency. */ public enum Type { STYLESHEET(StyleSheet.class), // JAVASCRIPT(JavaScript.class), // HTMLIMPORT(HtmlImport.class); private Class<? extends Annotation> annotationType; private Type(Class<? extends Annotation> annotationType) { this.annotationType = annotationType; } } private final Type type; private final String url; /** * Creates a new dependency of the given type, to be loaded from the given * URL. * <p> * The URL is passed through the translation mechanism before loading, so * custom protocols such as "vaadin://" can be used. * * @param type * the type of dependency, not <code>null</code> * @param url * the URL to load the dependency from, not <code>null</code> */ public Dependency(Type type, String url) { if (url == null) { throw new IllegalArgumentException("url cannot be null"); } assert type != null; this.type = type; this.url = url; } /** * Gets the untranslated URL for the dependency. * * @return the URL for the dependency */ public String getUrl() { return url; } /** * Gets the type of the dependency. * * @return the type of the dependency */ public Type getType() { return type; } /** * Finds all the URLs defined for the given class using annotations for the * given type, registers the URLs to the communication manager and adds the * registered dependencies to the given list. * * @param type * the type of dependencies to look for * @param cls * the class to scan * @param manager * a reference to the communication manager which tracks * dependencies * @param dependencies * the list to add registered dependencies to * * @return a stream of resource URLs in the order defined by the annotations */ @SuppressWarnings("deprecation") private static void findAndRegisterResources(Type type, Class<? extends ClientConnector> cls, LegacyCommunicationManager manager, List<Dependency> dependencies) { Annotation[] annotations = cls .getAnnotationsByType(type.annotationType); if (annotations != null) { for (Annotation annotation : annotations) { String[] resources; if (annotation instanceof StyleSheet) { resources = ((StyleSheet) annotation).value(); } else if (annotation instanceof JavaScript) { resources = ((JavaScript) annotation).value(); } else if (annotation instanceof HtmlImport) { resources = ((HtmlImport) annotation).value(); } else { throw new IllegalArgumentException( "Unknown annotation type: " + annotation.annotationType().getName()); } for (String resource : resources) { String url = manager.registerDependency(resource, cls); dependencies.add(new Dependency(type, url)); } } } } /** * Finds all the URLs defined for the given classes, registers the URLs to * the communication manager and returns the registered dependencies. * <p> * The returned collection contains all types of dependencies for each class * in the given list in the order the classes are in the list, i.e. all * dependencies for the first class before all dependencies for the next * class. * <p> * JavaScript dependencies are returned before HTML imports. * * @param connectorTypes * the collection of connector classes to scan * @param manager * a reference to the communication manager which tracks * dependencies * @return the list of found dependencies */ @SuppressWarnings("deprecation") public static List<Dependency> findDependencies( List<Class<? extends ClientConnector>> connectorTypes, LegacyCommunicationManager manager) { List<Dependency> dependencies = new ArrayList<>(); for (Class<? extends ClientConnector> connectorType : connectorTypes) { findAndRegisterResources(Type.JAVASCRIPT, connectorType, manager, dependencies); findAndRegisterResources(Type.HTMLIMPORT, connectorType, manager, dependencies); findAndRegisterResources(Type.STYLESHEET, connectorType, manager, dependencies); } return dependencies; } /** * Finds all the URLs defined for the given classes, registers the URLs to * the communication manager, passes the registered dependencies through any * defined filters and returns the filtered collection of dependencies to * load. * * @since 8.1 * @param connectorTypes * the collection of connector classes to scan * @param manager * a reference to the communication manager which tracks * dependencies * @param context * the context information for the filtering operation * @return the list of found and filtered dependencies */ public static List<Dependency> findAndFilterDependencies( List<Class<? extends ClientConnector>> connectorTypes, LegacyCommunicationManager manager, FilterContext context) { List<Dependency> dependencies = findDependencies(connectorTypes, manager); VaadinService service = context.getService(); for (DependencyFilter filter : service.getDependencyFilters()) { dependencies = filter.filter(dependencies, context); } return dependencies; } }