/* * Copyright 2011 The authors * 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.intellij.struts2.dom.struts.model; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiClass; import com.intellij.psi.util.CachedValue; import com.intellij.psi.util.CachedValueProvider; import com.intellij.psi.util.CachedValuesManager; import com.intellij.psi.util.PsiModificationTracker; import com.intellij.psi.xml.XmlFile; import com.intellij.struts2.dom.struts.StrutsRoot; import com.intellij.struts2.dom.struts.action.Action; import com.intellij.struts2.dom.struts.strutspackage.Interceptor; import com.intellij.struts2.dom.struts.strutspackage.InterceptorOrStackBase; import com.intellij.struts2.dom.struts.strutspackage.InterceptorStack; import com.intellij.struts2.dom.struts.strutspackage.StrutsPackage; import com.intellij.util.Function; import com.intellij.util.NotNullFunction; import com.intellij.util.Processor; import com.intellij.util.SmartList; import com.intellij.util.containers.ConcurrentFactoryMap; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.xml.DomFileElement; import com.intellij.util.xml.model.impl.DomModelImpl; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; /** * @author Yann Cébron */ class StrutsModelImpl extends DomModelImpl<StrutsRoot> implements StrutsModel { private static final NotNullFunction<DomFileElement<StrutsRoot>, StrutsRoot> ROOT_ELEMENT_MAPPER = new NotNullFunction<DomFileElement<StrutsRoot>, StrutsRoot>() { @NotNull public StrutsRoot fun(final DomFileElement<StrutsRoot> strutsRootDomFileElement) { return strutsRootDomFileElement.getRootElement(); } }; private static final Function<StrutsRoot, Collection<? extends StrutsPackage>> STRUTS_PACKAGE_COLLECTOR = new Function<StrutsRoot, Collection<? extends StrutsPackage>>() { public Collection<? extends StrutsPackage> fun(final StrutsRoot strutsRoot) { return strutsRoot.getPackages(); } }; private final StrutsModelImpl.ActionsForNamespaceCachedValuesProvider actionsCachedValueProvider = new ActionsForNamespaceCachedValuesProvider(); private static final Key<CachedValue<Map<String, List<Action>>>> ACTIONS_FOR_NAMESPACE = Key.create("STRUTS2_ACTIONS_FOR_NAMESPACE"); /** * Dummy identifier for "all namespaces". */ @NonNls private static final String EMPTY_NAMESPACE = "STRUTS2_PLUGIN_EMPTY_NAMESPACE"; StrutsModelImpl(@NotNull final DomFileElement<StrutsRoot> strutsRootDomFileElement, @NotNull final Set<XmlFile> xmlFiles) { super(strutsRootDomFileElement, xmlFiles); } @NotNull public List<StrutsRoot> getMergedStrutsRoots() { return ContainerUtil.map(getRoots(), ROOT_ELEMENT_MAPPER); } @NotNull public List<StrutsPackage> getStrutsPackages() { return ContainerUtil.concat(getMergedStrutsRoots(), STRUTS_PACKAGE_COLLECTOR); } @NotNull public Set<InterceptorOrStackBase> getAllInterceptorsAndStacks() { final Set<InterceptorOrStackBase> interceptorOrStackBases = new HashSet<InterceptorOrStackBase>(); for (final StrutsPackage strutsPackage : getStrutsPackages()) { final List<InterceptorStack> interceptorList = strutsPackage.getInterceptorStacks(); interceptorOrStackBases.addAll(interceptorList); final List<Interceptor> interceptors = strutsPackage.getInterceptors(); interceptorOrStackBases.addAll(interceptors); } return interceptorOrStackBases; } @NotNull public List<Action> findActionsByName(@NotNull @NonNls final String name, @Nullable @NonNls final String namespace) { return ContainerUtil.findAll(getActionsForNamespace(namespace), new Condition<Action>() { public boolean value(final Action action) { return action.matchesPath(name); } }); } @NotNull public List<Action> findActionsByClass(@NotNull final PsiClass clazz) { return findActionsByClassInner(clazz, false); } private List<Action> findActionsByClassInner(final PsiClass clazz, final boolean skipOnFirst) { final List<Action> actionResultList = new SmartList<Action>(); for (final StrutsPackage strutsPackage : getStrutsPackages()) { for (final Action action : strutsPackage.getActions()) { final PsiClass actionClassValue = action.searchActionClass(); if (Comparing.equal(clazz, actionClassValue)) { actionResultList.add(action); if (skipOnFirst) { return actionResultList; } } } } return actionResultList; } @Override public boolean isActionClass(@NotNull final PsiClass clazz) { return !findActionsByClassInner(clazz, true).isEmpty(); } public List<Action> getActionsForNamespace(@Nullable @NonNls final String namespace) { CachedValue<Map<String, List<Action>>> packageToActionMap = myMergedModel.getUserData(ACTIONS_FOR_NAMESPACE); if (packageToActionMap == null) { packageToActionMap = CachedValuesManager.getManager(myMergedModel.getManager().getProject()) .createCachedValue(actionsCachedValueProvider, false); myMergedModel.putUserData(ACTIONS_FOR_NAMESPACE, packageToActionMap); } return packageToActionMap.getValue().get(StringUtil.notNullize(namespace, EMPTY_NAMESPACE)); } public boolean processActions(final Processor<Action> processor) { for (final StrutsPackage strutsPackage : getStrutsPackages()) { List<Action> actions = strutsPackage.getActions(); if (!ContainerUtil.process(actions, processor)) return false; } return true; } private class ActionsForNamespaceCachedValuesProvider implements CachedValueProvider<Map<String, List<Action>>> { public Result<Map<String, List<Action>>> compute() { final Map<String, List<Action>> map = new ConcurrentFactoryMap<String, List<Action>>() { @Override protected List<Action> create(final String namespace) { final List<Action> actionResultList = new SmartList<Action>(); for (final StrutsPackage strutsPackage : getStrutsPackages()) { if (Comparing.equal(namespace, EMPTY_NAMESPACE) || Comparing.equal(namespace, strutsPackage.searchNamespace())) { actionResultList.addAll(strutsPackage.getActions()); } } return actionResultList; } }; return Result.create(map, PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT); } } }