//
// Copyright 2009 Robin Komiwes, Bruno Verachten, Christophe Cordenier
//
// 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.wooki.services;
import java.util.List;
import org.apache.tapestry5.Asset;
import org.apache.tapestry5.SymbolConstants;
import org.apache.tapestry5.hibernate.HibernateTransactionAdvisor;
import org.apache.tapestry5.internal.InternalConstants;
import org.apache.tapestry5.internal.services.ComponentInstanceProcessor;
import org.apache.tapestry5.internal.services.LinkSource;
import org.apache.tapestry5.ioc.Configuration;
import org.apache.tapestry5.ioc.Invocation;
import org.apache.tapestry5.ioc.MappedConfiguration;
import org.apache.tapestry5.ioc.MethodAdvice;
import org.apache.tapestry5.ioc.MethodAdviceReceiver;
import org.apache.tapestry5.ioc.OrderedConfiguration;
import org.apache.tapestry5.ioc.Resource;
import org.apache.tapestry5.ioc.ServiceBinder;
import org.apache.tapestry5.ioc.annotations.Autobuild;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.tapestry5.ioc.annotations.Match;
import org.apache.tapestry5.ioc.annotations.SubModule;
import org.apache.tapestry5.ioc.annotations.Symbol;
import org.apache.tapestry5.ioc.internal.services.ClasspathResourceSymbolProvider;
import org.apache.tapestry5.ioc.services.ClasspathURLConverter;
import org.apache.tapestry5.ioc.services.Coercion;
import org.apache.tapestry5.ioc.services.CoercionTuple;
import org.apache.tapestry5.ioc.services.SymbolProvider;
import org.apache.tapestry5.ioc.services.ThreadLocale;
import org.apache.tapestry5.services.AssetSource;
import org.apache.tapestry5.services.ComponentClasses;
import org.apache.tapestry5.services.ComponentEventResultProcessor;
import org.apache.tapestry5.services.ComponentRequestFilter;
import org.apache.tapestry5.services.Dispatcher;
import org.apache.tapestry5.services.Environment;
import org.apache.tapestry5.services.EnvironmentalShadowBuilder;
import org.apache.tapestry5.services.InvalidationEventHub;
import org.apache.tapestry5.services.PageRenderRequestFilter;
import org.apache.tapestry5.services.Response;
import org.apache.tapestry5.services.Traditional;
import org.apache.tapestry5.services.UpdateListenerHub;
import org.apache.tapestry5.services.messages.PropertiesFileParser;
import org.apache.tapestry5.upload.services.MultipartDecoder;
import org.apache.tapestry5.util.StringToEnumCoercion;
import org.springframework.security.core.userdetails.UserDetailsService;
import com.wooki.AppendPosition;
import com.wooki.WookiSymbolsConstants;
import com.wooki.core.services.CoreModule;
import com.wooki.domain.biz.BookManager;
import com.wooki.domain.biz.BookManagerImpl;
import com.wooki.domain.biz.ChapterManager;
import com.wooki.domain.biz.ChapterManagerImpl;
import com.wooki.domain.biz.CommentManager;
import com.wooki.domain.biz.CommentManagerImpl;
import com.wooki.domain.biz.UserManager;
import com.wooki.domain.biz.UserManagerImpl;
import com.wooki.services.activity.ActivityModule;
import com.wooki.services.activity.ActivitySourceType;
import com.wooki.services.db.DataModule;
import com.wooki.services.feeds.FeedModule;
import com.wooki.services.internal.TapestryOverrideModule;
import com.wooki.services.parsers.DOMManager;
import com.wooki.services.parsers.DOMManagerImpl;
import com.wooki.services.security.ActivationContextManager;
import com.wooki.services.security.ActivationContextManagerImpl;
import com.wooki.services.security.SecureActivationContextRequestFilter;
import com.wooki.services.security.UserDetailsServiceImpl;
import com.wooki.services.security.spring.SecurityUrlSource;
import com.wooki.services.security.spring.SecurityUrlSourceImpl;
@SubModule(
{ TapestryOverrideModule.class, DataModule.class, ActivityModule.class, FeedModule.class,
CoreModule.class })
public class WookiModule<T>
{
/**
* Used to stored the last view page in session.
*/
public static final String VIEW_REFERER = "tapestry-view.referer";
private final InvalidationEventHub classesInvalidationEventHub;
private final EnvironmentalShadowBuilder environmentalBuilder;
private final Environment environment;
public WookiModule(@ComponentClasses InvalidationEventHub classesInvalidationEventHub,
Environment environment, EnvironmentalShadowBuilder environmentalBuilder)
{
this.classesInvalidationEventHub = classesInvalidationEventHub;
this.environmentalBuilder = environmentalBuilder;
this.environment = environment;
}
public void contributeApplicationDefaults(MappedConfiguration<String, String> conf)
{
conf.add(SymbolConstants.SUPPORTED_LOCALES, "en");
conf.add(SymbolConstants.FORCE_ABSOLUTE_URIS, "true");
conf.add(SymbolConstants.APPLICATION_VERSION, "0.4");
conf.add(WookiSymbolsConstants.ERROR_WOOKI_EXCEPTION_REPORT, "error/generic");
}
public static void bind(ServiceBinder binder)
{
binder.bind(StartupService.class, StartupServiceImpl.class).preventReloading().eagerLoad();
binder.bind(UserDetailsService.class, UserDetailsServiceImpl.class);
binder.bind(SecurityUrlSource.class, SecurityUrlSourceImpl.class);
binder.bind(UploadMediaService.class, UploadMediaServiceImpl.class);
binder.bind(DOMManager.class, DOMManagerImpl.class);
binder.bind(WookiViewRefererFilter.class);
// domain biz
binder.bind(BookManager.class, BookManagerImpl.class);
binder.bind(ChapterManager.class, ChapterManagerImpl.class);
binder.bind(CommentManager.class, CommentManagerImpl.class);
binder.bind(UserManager.class, UserManagerImpl.class);
// Bind the service
binder.bind(EnumServiceLocator.class, EnumServiceLocatorImpl.class);
}
/**
* Build messages catalog service for services.
*/
public ServicesMessages buildServicesMessages(
@Symbol(SymbolConstants.APPLICATION_CATALOG) Resource appCatalogResource,
@Inject ClasspathURLConverter urlConverter, @Inject ThreadLocale locale,
@Inject LinkSource linkSource, @Inject UpdateListenerHub listenerHub,
@Inject PropertiesFileParser fileParse)
{
ServicesMessages messages = new ServicesMessagesImpl(appCatalogResource, urlConverter,
locale, linkSource, fileParse);
listenerHub.addUpdateListener(messages);
return messages;
}
public ActivationContextManager buildActivationContextManager(
@Autobuild ActivationContextManagerImpl service)
{
// This covers invalidations due to changes to classes
classesInvalidationEventHub.addInvalidationListener(service);
return service;
}
/**
* Allow to return error code instance.
*
* @param componentInstanceProcessor
* @param configuration
*/
public void contributeComponentEventResultProcessor(
@Traditional @ComponentInstanceProcessor ComponentEventResultProcessor componentInstanceProcessor,
MappedConfiguration<Class, ComponentEventResultProcessor> configuration)
{
configuration.addInstance(HttpError.class, HttpErrorResultProcessor.class);
}
/**
* Add a filter to secure activation context in request.
*
* @param filters
* @param manager
* @param response
*/
public static void contributeComponentRequestHandler(
OrderedConfiguration<ComponentRequestFilter> filters, ActivationContextManager manager,
Response response, MultipartDecoder decoder)
{
filters.add("secureActivationContextFilter", new SecureActivationContextRequestFilter(
manager, response, decoder));
}
/**
* Wooki Symbols default
*/
public static void contributeFactoryDefaults(MappedConfiguration<String, String> configuration)
{
configuration.add(
WookiSymbolsConstants.ERROR_UNHANDLED_BROWSER_PAGE,
"error/unhandledbrowser");
}
public static void contributeHibernateEntityPackageManager(Configuration<String> configuration,
@Inject @Symbol(InternalConstants.TAPESTRY_APP_PACKAGE_PARAM) String rootPackage)
{
configuration.add(rootPackage + ".domain.model");
}
public static void contributeMasterDispatcher(OrderedConfiguration<Dispatcher> configuration)
{
configuration.addInstance("UploadedAsset", UploadedAssetDispatcher.class, "before:Asset");
}
public static void contributeSymbolSource(OrderedConfiguration<SymbolProvider> providers)
{
providers.add("tapestryConfiguration", new ClasspathResourceSymbolProvider(
"config/tapestry.properties"));
providers.add("springSecurity", new ClasspathResourceSymbolProvider(
"config/security.properties"));
}
/**
* Store the last view page in session.
*/
public static void contributePageRenderRequestHandler(
OrderedConfiguration<PageRenderRequestFilter> filters, WookiViewRefererFilter vrFilter)
{
filters.add("ViewRefererFilter", vrFilter);
filters.addInstance("IESupport", BrowserSelection.class);
}
/**
* Add coercion tuple for parameter types...
*
* @param configuration
*/
public static void contributeTypeCoercer(Configuration<CoercionTuple> configuration)
{
addTuple(configuration, String.class, ActivitySourceType.class, StringToEnumCoercion
.create(ActivitySourceType.class));
addTuple(configuration, String.class, AppendPosition.class, StringToEnumCoercion
.create(AppendPosition.class));
}
/**
* Add request that shouldn't generate a referer.
*
* @param excludePattern
*/
public static void contributeWookiViewRefererFilter(Configuration<String> excludePattern)
{
excludePattern.add("signin");
excludePattern.add("signup");
excludePattern.add(".*edit.*");
excludePattern.add("dev.*");
excludePattern.add("error.*");
}
/**
* Add jQuery in no conflict mode to default JavaScript Stack
*
* @param receiver
* @throws NoSuchMethodException
* @throws SecurityException
*/
@SuppressWarnings("unchecked")
@Match("ClientInfrastructure")
public static void adviseClientInfrastructure(MethodAdviceReceiver receiver,
final AssetSource source) throws SecurityException, NoSuchMethodException
{
MethodAdvice advice = new MethodAdvice()
{
public void advise(Invocation invocation)
{
invocation.proceed();
List<Asset> jsStack = (List<Asset>) invocation.getResult();
jsStack.add(0, source.getClasspathAsset("context:static/js/jquery.noconflict.js"));
jsStack.add(0, source.getClasspathAsset("context:static/js/jquery-1.3.2.min.js"));
jsStack.add(source.getClasspathAsset("context:static/js/wooki.js"));
jsStack.add(source.getClasspathAsset("context:static/js/wooki-messages.js"));
}
};
receiver.adviseMethod(receiver.getInterface().getMethod("getJavascriptStack"), advice);
}
@Match("*Manager")
public static void adviseTransactions(HibernateTransactionAdvisor advisor,
MethodAdviceReceiver receiver)
{
advisor.addTransactionCommitAdvice(receiver);
}
private static <S, T> void addTuple(Configuration<CoercionTuple> configuration,
Class<S> sourceType, Class<T> targetType, Coercion<S, T> coercion)
{
CoercionTuple<S, T> tuple = new CoercionTuple<S, T>(sourceType, targetType, coercion);
configuration.add(tuple);
}
}