001// Copyright 2009 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.internal.services; 016 017import java.util.HashSet; 018import java.util.Set; 019 020import org.apache.tapestry5.SymbolConstants; 021import org.apache.tapestry5.internal.services.ComponentDependencyRegistry.DependencyType; 022import org.apache.tapestry5.ioc.annotations.Symbol; 023import org.apache.tapestry5.model.ComponentModel; 024import org.apache.tapestry5.services.ComponentClassResolver; 025 026public class ComponentModelSourceImpl implements ComponentModelSource 027{ 028 private final ComponentClassResolver resolver; 029 030 private final ComponentInstantiatorSource source; 031 032 private final ComponentDependencyRegistry componentDependencyRegistry; 033 034 private final PageSource pageSource; 035 036 private final boolean multipleClassLoaders; 037 038 private final static ThreadLocal<Set<String>> CALL_STACK = 039 ThreadLocal.withInitial(HashSet::new); 040 041 public ComponentModelSourceImpl(ComponentClassResolver resolver, ComponentInstantiatorSource source, 042 ComponentDependencyRegistry componentDependencyRegistry, 043 PageSource pageSource, 044 @Symbol(SymbolConstants.PRODUCTION_MODE) boolean productionMode, 045 @Symbol(SymbolConstants.MULTIPLE_CLASSLOADERS) boolean multipleClassLoaders) 046 { 047 this.resolver = resolver; 048 this.source = source; 049 this.componentDependencyRegistry = componentDependencyRegistry; 050 this.pageSource = pageSource; 051 this.multipleClassLoaders = !productionMode && multipleClassLoaders; 052 } 053 054 public ComponentModel getModel(String componentClassName) 055 { 056 if (multipleClassLoaders && isPage(componentClassName)) 057 { 058 final Set<String> superclasses = componentDependencyRegistry.getDependencies( 059 componentClassName, DependencyType.SUPERCLASS); 060 061 if (!superclasses.isEmpty()) 062 { 063 final String superclass = superclasses.iterator().next(); 064 final Set<String> callStack = CALL_STACK.get(); 065 if (!callStack.contains(superclass) && isPage(superclass)) 066 { 067 callStack.add(superclass); 068 getModel(superclass); 069 try 070 { 071 pageSource.getPage(resolver.getLogicalName(componentClassName)); 072 } 073 catch (IllegalStateException e) 074 { 075 // This can be thrown in PageSourceImpl in case an 076 // infinite method call recursion is detected. In 077 // that case, the page instance is already created, 078 // so the objective of the line above is already 079 // fulfilled and we can safely ignore the exception 080 } 081 callStack.remove(superclass); 082 } 083 } 084 } 085 return source.getInstantiator(componentClassName).getModel(); 086 } 087 088 public ComponentModel getPageModel(String pageName) 089 { 090 return getModel(resolver.resolvePageNameToClassName(pageName)); 091 } 092 093 private boolean isPage(String componentClassName) 094 { 095 return componentClassName.contains(".pages."); 096 } 097}