/*
* Copyright 2000-2007 JetBrains s.r.o.
*
* 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.persistence.util;
import com.intellij.facet.Facet;
import com.intellij.facet.FacetManager;
import com.intellij.javaee.util.JamCommonUtil;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.persistence.PersistenceHelper;
import com.intellij.persistence.facet.PersistenceFacetBase;
import com.intellij.persistence.facet.PersistenceFacetConfiguration;
import com.intellij.persistence.model.*;
import com.intellij.persistence.roles.PersistenceClassRole;
import com.intellij.persistence.roles.PersistenceClassRoleEnum;
import com.intellij.persistence.roles.PersistenceRoleHolder;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.*;
import com.intellij.util.*;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.xml.DomElement;
import com.intellij.util.xml.GenericValue;
import gnu.trove.THashSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
/**
* @author Gregory.Shrago
*/
public class PersistenceCommonUtil {
private PersistenceCommonUtil() { }
public static List<PersistenceFacetBase<PersistenceFacetConfiguration, PersistencePackage>> getAllPersistenceFacets(final Project project) {
final List<PersistenceFacetBase<PersistenceFacetConfiguration, PersistencePackage>> result = new ArrayList<PersistenceFacetBase<PersistenceFacetConfiguration, PersistencePackage>>();
for (Module module : ModuleManager.getInstance(project).getModules()) {
result.addAll(getAllPersistenceFacets(module));
}
return result;
}
public static List<PersistenceFacetBase<PersistenceFacetConfiguration, PersistencePackage>> getAllPersistenceFacets(final Module module) {
final List<PersistenceFacetBase<PersistenceFacetConfiguration, PersistencePackage>> result = new ArrayList<PersistenceFacetBase<PersistenceFacetConfiguration, PersistencePackage>>();
for (Facet facet : FacetManager.getInstance(module).getAllFacets()) {
if (facet instanceof PersistenceFacetBase) {
result.add((PersistenceFacetBase<PersistenceFacetConfiguration, PersistencePackage>)facet);
}
}
return result;
}
private static Key<CachedValue<List<PersistenceFacetBase<PersistenceFacetConfiguration, PersistencePackage>>>> MODULE_PERSISTENCE_FACETS = Key.create("MODULE_PERSISTENCE_FACETS");
@NotNull
public static List<PersistenceFacetBase<PersistenceFacetConfiguration, PersistencePackage>> getAllPersistenceFacetsWithDependencies(final Module module) {
CachedValue<List<PersistenceFacetBase<PersistenceFacetConfiguration, PersistencePackage>>> cachedValue =
module.getUserData(MODULE_PERSISTENCE_FACETS);
if (cachedValue == null) {
cachedValue = PsiManager.getInstance(module.getProject()).getCachedValuesManager().createCachedValue(new CachedValueProvider<List<PersistenceFacetBase<PersistenceFacetConfiguration, PersistencePackage>>>() {
public Result<List<PersistenceFacetBase<PersistenceFacetConfiguration, PersistencePackage>>> compute() {
final Set<PersistenceFacetBase<PersistenceFacetConfiguration, PersistencePackage>> facets = new THashSet<PersistenceFacetBase<PersistenceFacetConfiguration, PersistencePackage>>();
for (Module depModule : JamCommonUtil.getAllDependentModules(module)) {
facets.addAll(getAllPersistenceFacets(depModule));
}
return new Result<List<PersistenceFacetBase<PersistenceFacetConfiguration, PersistencePackage>>>(new ArrayList<PersistenceFacetBase<PersistenceFacetConfiguration, PersistencePackage>>(facets),
ProjectRootManager.getInstance(module.getProject()));
}
}, false);
module.putUserData(MODULE_PERSISTENCE_FACETS, cachedValue);
}
return cachedValue.getValue();
}
public static PersistenceModelBrowser createSameUnitsModelBrowser(final PsiElement sourceElement, final PersistenceClassRoleEnum sourceType, final PersistenceClassRoleEnum type) {
final PsiClass sourceClass;
final Set<PersistencePackage> unitSet;
if (sourceElement == null || (sourceClass = PsiTreeUtil.getParentOfType(sourceElement, PsiClass.class, false)) == null) {
unitSet = null;
}
else {
unitSet = getAllPersistenceUnits(sourceClass, sourceType, new THashSet<PersistencePackage>());
}
return createUnitsAndTypeMapper(unitSet, type);
}
public static PersistenceModelBrowser createSameUnitsModelBrowser(final DomElement sourceDom, final PersistenceClassRoleEnum type) {
final Set<PersistencePackage> unitSet;
final DomElement rootElement;
if (sourceDom == null || !((rootElement = sourceDom.getRoot().getRootElement()) instanceof PersistenceMappings)) {
unitSet = null;
}
else {
unitSet = new THashSet<PersistencePackage>(PersistenceHelper.getHelper().getSharedModelBrowser().getPersistenceUnits((PersistenceMappings)rootElement));
}
return createUnitsAndTypeMapper(unitSet, type);
}
public static PersistenceModelBrowser createUnitsAndTypeMapper(final Set<PersistencePackage> unitSet,
final PersistenceClassRoleEnum type) {
return PersistenceHelper.getHelper().createModelBrowser().setRoleFilter(new Condition<PersistenceClassRole>() {
public boolean value(final PersistenceClassRole role) {
final PersistentObject object = role.getPersistentObject();
final PersistenceClassRoleEnum roleType = role.getType();
return roleType != PersistenceClassRoleEnum.ENTITY_LISTENER && object != null && (type == null || roleType == type) && (unitSet == null || unitSet.contains(role.getPersistenceUnit()));
}
});
}
public static PersistenceModelBrowser createFacetAndUnitModelBrowser(final PersistenceFacetBase facet,
final PersistencePackage unit,
final PersistenceClassRoleEnum type) {
return PersistenceHelper.getHelper().createModelBrowser().setRoleFilter(new Condition<PersistenceClassRole>() {
public boolean value(final PersistenceClassRole role) {
final PersistentObject object = role.getPersistentObject();
return object != null && (type == null || role.getType() == type) && (unit == null || unit.equals(role.getPersistenceUnit())) &&
(facet == null || facet.equals(role.getFacet()));
}
});
}
@Nullable
public static PsiType getTargetEntityType(final PsiMember psiMember) {
return getTargetEntityType(PropertyUtil.getPropertyType(psiMember));
}
@Nullable
public static PsiType getTargetEntityType(final PsiType type) {
final Pair<JavaContainerType, PsiType> containerType = getContainerType(type);
return containerType.getSecond();
}
public static <T extends Collection<PersistencePackage>> T getAllPersistenceUnits(final PsiClass sourceClass,
final PersistenceClassRoleEnum type,
final T result) {
for (PersistenceClassRole role : getPersistenceRoles(sourceClass)) {
if (type == null || role.getType() == type) {
ContainerUtil.addIfNotNull(role.getPersistenceUnit(), result);
}
}
return result;
}
public static PersistenceClassRole[] getPersistenceRoles(final PsiClass aClass) {
if (aClass == null) return PersistenceClassRole.EMPTY_ARRAY;
return PersistenceRoleHolder.getInstance(aClass.getProject()).getRoles(aClass);
}
@NotNull
public static <T extends PersistencePackage, V extends PersistenceMappings> Collection<V> getDomEntityMappings(final Class<V> mappingsClass,
final T unit, final PersistenceFacetBase<?, T> facet) {
final THashSet<V> result = new THashSet<V>();
for (PersistenceMappings mappings : facet.getDefaultEntityMappings(unit)) {
if (ReflectionCache.isAssignable(mappingsClass, mappings.getClass())) {
result.add((V)mappings);
}
}
for (GenericValue<V> value : unit.getModelHelper().getMappingFiles(mappingsClass)) {
ContainerUtil.addIfNotNull(value.getValue(), result);
}
return result;
}
public static boolean isSameTable(final TableInfoProvider table1, final TableInfoProvider table2) {
if (table1 == null || table2 == null) return false;
final String name1 = table1.getTableName().getValue();
return StringUtil.isNotEmpty(name1) &&
Comparing.equal(name1, table2.getTableName().getValue()) &&
Comparing.equal(table1.getSchema().getValue(), table2.getSchema().getValue()) &&
Comparing.equal(table1.getCatalog().getValue(), table2.getCatalog().getValue());
}
public static String getUniqueId(final PsiElement psiElement) {
final VirtualFile virtualFile = psiElement == null? null : PsiUtil.getVirtualFile(psiElement);
return virtualFile == null ? "" : virtualFile.getUrl();
}
public static String getMultiplicityString(final boolean optional, final boolean many) {
final String first = (optional ? "0" : "1");
final String last = (many ? "*" : "1");
return first.equals(last) ? first : first + ".." + last;
}
public static <T, V extends Collection<T>> V mapPersistenceRoles(final V result, final Project project, final PersistenceFacetBase facet, final PersistencePackage unit, final Function<PersistenceClassRole, T> mapper) {
final Collection<PersistenceClassRole> allRoles = PersistenceRoleHolder.getInstance(project).getClassRoleManager()
.getUserData(PersistenceRoleHolder.PERSISTENCE_CLASS_ROLES_KEY, PersistenceRoleHolder.PERSISTENCE_ALL_ROLES_DATA_KEY);
if (allRoles != null) {
for (PersistenceClassRole role : allRoles) {
if ((facet == null || facet == role.getFacet()) && (unit == null || unit == role.getPersistenceUnit())) {
ContainerUtil.addIfNotNull(mapper.fun(role), result);
}
}
}
return result;
}
public static boolean haveCorrespondingMultiplicity(final PersistentRelationshipAttribute a1, final PersistentRelationshipAttribute a2) {
return a1.getAttributeModelHelper().getRelationshipType().corresponds(a2.getAttributeModelHelper().getRelationshipType());
}
public static <T extends PersistencePackage> boolean processNamedQueries(final PersistenceFacetBase<?, T> facet,
final boolean nativeQueries, final Processor<PersistenceQuery> processor) {
return processNamedQueries(nativeQueries? PersistenceRoleHolder.PERSISTENCE_ALL_NATIVE_QUERIES_DATA_KEY : PersistenceRoleHolder.PERSISTENCE_ALL_QUERIES_DATA_KEY, facet, processor);
}
private static <T extends PersistencePackage> boolean processNamedQueries(final Key<Map<PersistenceFacetBase, Collection<PersistenceQuery>>> queriesDataKey,
final PersistenceFacetBase<?, T> facet,
final Processor<PersistenceQuery> processor) {
final Map<PersistenceFacetBase, Collection<PersistenceQuery>> namedQueriesMap = PersistenceRoleHolder.getInstance(facet.getModule().getProject())
.getClassRoleManager()
.getUserData(PersistenceRoleHolder.PERSISTENCE_CLASS_ROLES_KEY, queriesDataKey);
if (namedQueriesMap != null) {
final Collection<PersistenceQuery> queries = namedQueriesMap.get(facet);
if (queries != null && !ContainerUtil.process(queries, processor)) {
return false;
}
}
return true;
}
@NotNull
public static Pair<JavaContainerType, PsiType> getContainerType(final PsiType type) {
if (type instanceof PsiArrayType) {
return Pair.create(JavaContainerType.ARRAY, ((PsiArrayType)type).getComponentType());
}
final PsiClassType.ClassResolveResult classResolveResult = type instanceof PsiClassType ? ((PsiClassType)type).resolveGenerics() : null;
if (classResolveResult == null) return Pair.create(null, type);
final PsiClass psiClass = classResolveResult.getElement();
if (psiClass == null) return Pair.create(null, type);
final PsiManager manager = psiClass.getManager();
final GlobalSearchScope scope = manager.getProject().getAllScope();
for (JavaContainerType collectionType : JavaContainerType.values()) {
if (collectionType == JavaContainerType.ARRAY) continue;
final PsiClass aClass = manager.findClass(collectionType.getJavaBaseClassName(), scope);
if (aClass != null && (manager.areElementsEquivalent(aClass, psiClass) || psiClass.isInheritor(aClass, true))) {
final PsiTypeParameter[] typeParameters = aClass.getTypeParameters();
assert !PsiUtil.getLanguageLevel(aClass).hasEnumKeywordAndAutoboxing() || typeParameters.length > 0;
final PsiType entityType;
if (typeParameters.length > 0) {
entityType = TypeConversionUtil.getSuperClassSubstitutor(aClass, psiClass, classResolveResult.getSubstitutor()).substitute(typeParameters[typeParameters.length - 1]);
}
else {
entityType = PsiType.getJavaLangObject(manager, scope);
}
return Pair.create(collectionType, entityType);
}
}
return Pair.create(null, type);
}
public static Query<PersistentObject> queryPersistentObjects(final PersistenceMappings mappings) {
return new ExecutorsQuery<PersistentObject, PersistenceMappings>(mappings, Collections.<QueryExecutor<PersistentObject, PersistenceMappings>>singletonList(
new QueryExecutor<PersistentObject, PersistenceMappings>() {
public boolean execute(PersistenceMappings queryParameters, Processor<PersistentObject> consumer) {
if (!ContainerUtil.process(queryParameters.getModelHelper().getPersistentEntities(), consumer)) return false;
if (!ContainerUtil.process(queryParameters.getModelHelper().getPersistentSuperclasses(), consumer)) return false;
if (!ContainerUtil.process(queryParameters.getModelHelper().getPersistentEmbeddables(), consumer)) return false;
return true;
}
}));
}
@Nullable
public static PsiClass getTargetClass(final PersistentRelationshipAttribute attribute) {
final GenericValue<PsiClass> classValue = attribute.getTargetEntityClass();
final PsiClass targetClass;
if (classValue.getStringValue() != null) {
targetClass = classValue.getValue();
}
else {
final PsiType entityType = getTargetEntityType(attribute.getPsiMember());
targetClass = entityType instanceof PsiClassType ? ((PsiClassType)entityType).resolve() : null;
}
return targetClass;
}
@Nullable
public static PsiClass getTargetClass(final PersistentEmbeddedAttribute attribute) {
final GenericValue<PsiClass> classValue = attribute.getTargetEmbeddableClass();
final PsiClass targetClass;
if (classValue.getStringValue() != null) {
targetClass = classValue.getValue();
}
else {
final PsiType entityType = PropertyUtil.getPropertyType(attribute.getPsiMember());
targetClass = entityType instanceof PsiClassType ? ((PsiClassType)entityType).resolve() : null;
}
return targetClass;
}
}