001// Copyright 2011-2013 The Apache Software Foundation 002// 003// Licensed under the Apache License, Version 2.0 (the "License"); 004// you may not use this file except in compliance with the License. 005// You may obtain a copy of the License at 006// 007// http://www.apache.org/licenses/LICENSE-2.0 008// 009// Unless required by applicable law or agreed to in writing, software 010// distributed under the License is distributed on an "AS IS" BASIS, 011// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 012// See the License for the specific language governing permissions and 013// limitations under the License. 014 015package org.apache.tapestry5.services.javascript; 016 017import org.apache.tapestry5.Asset; 018import org.apache.tapestry5.func.F; 019import org.apache.tapestry5.func.Flow; 020import org.apache.tapestry5.func.Mapper; 021import org.apache.tapestry5.func.Predicate; 022import org.apache.tapestry5.ioc.ServiceBinder; 023import org.apache.tapestry5.ioc.ServiceBindingOptions; 024import org.apache.tapestry5.ioc.annotations.UsesOrderedConfiguration; 025import org.apache.tapestry5.ioc.internal.util.InternalUtils; 026import org.apache.tapestry5.services.AssetSource; 027 028import java.util.List; 029 030/** 031 * An extensible implementation of {@link JavaScriptStack} that can be used as the implementation of a service. 032 * The contributions to the service are used to supply the libraries, stylesheets, and initialization for a 033 * JavaScriptStack, allowing the stack to be more dynamically configured. In practice, one will use 034 * {@link ServiceBinder#bind(Class, Class)} and {@link ServiceBindingOptions#withMarker(Class...)} to construct the 035 * service, then use the marker annotation to inject the service when contributing the service into to the 036 * {@link JavaScriptStackSource}. 037 * <p/> 038 * A limitation of this implementation is that the contributed assets are not localized at all. 039 * 040 * @see StackExtension 041 * @since 5.3 042 */ 043@UsesOrderedConfiguration(StackExtension.class) 044public class ExtensibleJavaScriptStack implements JavaScriptStack 045{ 046 private final AssetSource assetSource; 047 048 private final List<Asset> libraries; 049 050 private final List<StylesheetLink> stylesheets; 051 052 private final List<String> stacks; 053 054 private final List<String> modules; 055 056 private final String initialization; 057 058 private final Predicate<StackExtension> by(final StackExtensionType type) 059 { 060 return new Predicate<StackExtension>() 061 { 062 public boolean accept(StackExtension element) 063 { 064 return element.type == type; 065 } 066 }; 067 } 068 069 private final Mapper<StackExtension, String> extractValue = new Mapper<StackExtension, String>() 070 { 071 public String map(StackExtension element) 072 { 073 return element.value; 074 } 075 076 ; 077 }; 078 079 private final Mapper<String, Asset> stringToAsset = new Mapper<String, Asset>() 080 { 081 public Asset map(String value) 082 { 083 return assetSource.getExpandedAsset(value); 084 } 085 086 ; 087 }; 088 089 private final Mapper<Asset, StylesheetLink> assetToStylesheetLink = new Mapper<Asset, StylesheetLink>() 090 { 091 public StylesheetLink map(Asset asset) 092 { 093 return new StylesheetLink(asset); 094 } 095 096 ; 097 }; 098 099 public ExtensibleJavaScriptStack(AssetSource assetSource, List<StackExtension> configuration) 100 { 101 this.assetSource = assetSource; 102 103 Flow<StackExtension> extensions = F.flow(configuration); 104 105 libraries = extensions.filter(by(StackExtensionType.LIBRARY)).map(extractValue).map(stringToAsset).toList(); 106 107 stacks = extensions.filter(by(StackExtensionType.STACK)).map(extractValue).toList(); 108 109 modules = extensions.filter(by(StackExtensionType.MODULE)).map(extractValue).toList(); 110 111 stylesheets = extensions.filter(by(StackExtensionType.STYLESHEET)).map(extractValue).map(stringToAsset) 112 .map(assetToStylesheetLink).toList(); 113 114 List<String> initializations = extensions.filter(by(StackExtensionType.INITIALIZATION)).map(extractValue) 115 .toList(); 116 117 initialization = initializations.isEmpty() ? null : InternalUtils.join(initializations, "\n"); 118 } 119 120 public List<String> getStacks() 121 { 122 return stacks; 123 } 124 125 public List<Asset> getJavaScriptLibraries() 126 { 127 return libraries; 128 } 129 130 public List<StylesheetLink> getStylesheets() 131 { 132 return stylesheets; 133 } 134 135 public String getInitialization() 136 { 137 return initialization; 138 } 139 140 public List<String> getModules() 141 { 142 return modules; 143 } 144}