blob: 3e60d22711d2f938668b479e89e116b4c2ea2467 [file] [log] [blame]
/*
* Copyright 2000-2010 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.lang.ant.dom;
import com.intellij.lang.properties.IProperty;
import com.intellij.lang.properties.PropertiesImplUtil;
import com.intellij.lang.properties.psi.PropertiesFile;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.pom.references.PomService;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiFileSystemItem;
import com.intellij.util.PathUtil;
import com.intellij.util.containers.HashMap;
import com.intellij.util.xml.Attribute;
import com.intellij.util.xml.Convert;
import com.intellij.util.xml.DomTarget;
import com.intellij.util.xml.GenericAttributeValue;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
/**
* @author Eugene Zhuravlev
* Date: Apr 21, 2010
*/
public abstract class AntDomProperty extends AntDomClasspathComponent implements PropertiesProvider{
private volatile Map<String, String> myCachedProperties;
private volatile ClassLoader myCachedLoader;
@Attribute("value")
@Convert(value = AntDomPropertyValueConverter.class)
public abstract GenericAttributeValue<Object> getValue();
@Attribute("location")
@Convert(value = AntPathConverter.class)
public abstract GenericAttributeValue<PsiFileSystemItem> getLocation();
@Attribute("resource")
public abstract GenericAttributeValue<String> getResource();
@Attribute("file")
@Convert(value = AntPathValidatingConverter.class)
public abstract GenericAttributeValue<PsiFileSystemItem> getFile();
@Attribute("url")
public abstract GenericAttributeValue<String> getUrl();
@Attribute("environment")
public abstract GenericAttributeValue<String> getEnvironment();
@Attribute("prefix")
public abstract GenericAttributeValue<String> getPrefix();
@Attribute("relative")
public abstract GenericAttributeValue<String> getRelative();
@Attribute("basedir")
public abstract GenericAttributeValue<String> getbasedir();
@NotNull
public final Iterator<String> getNamesIterator() {
final String prefix = getPropertyPrefixValue();
final Iterator<String> delegate = buildProperties().keySet().iterator();
if (prefix == null) {
return delegate;
}
return new Iterator<String>() {
public boolean hasNext() {
return delegate.hasNext();
}
public String next() {
return prefix + delegate.next();
}
public void remove() {
delegate.remove();
}
};
}
public PsiElement getNavigationElement(final String propertyName) {
DomTarget domTarget = DomTarget.getTarget(this);
if (domTarget == null) {
final GenericAttributeValue<String> environment = getEnvironment();
if (environment.getRawText() != null) {
domTarget = DomTarget.getTarget(this, environment);
}
if (domTarget == null) {
final GenericAttributeValue<String> resource = getResource();
if (resource.getRawText() != null) {
domTarget = DomTarget.getTarget(this, resource);
}
}
}
if (domTarget != null) {
final PsiElement psi = PomService.convertToPsi(domTarget);
if (psi != null) {
return psi;
}
}
final PsiFileSystemItem psiFile = getFile().getValue();
if (psiFile != null) {
final String prefix = getPropertyPrefixValue();
String _propertyName = propertyName;
if (prefix != null) {
if (!propertyName.startsWith(prefix)) {
return null;
}
_propertyName = propertyName.substring(prefix.length());
}
final PropertiesFile pf = toPropertiesFile(psiFile);
if (pf != null) {
final IProperty property = pf.findPropertyByKey(_propertyName);
return property != null? property.getPsiElement() : null;
}
}
return null;
}
@Nullable
public final String getPropertyValue(String propertyName) {
final String prefix = getPropertyPrefixValue();
if (prefix != null) {
if (!propertyName.startsWith(prefix)) {
return null;
}
propertyName = propertyName.substring(prefix.length());
}
return buildProperties().get(propertyName);
}
private Map<String, String> buildProperties() {
Map<String, String> result = myCachedProperties;
if (result != null) {
return result;
}
result = Collections.emptyMap();
final String propertyName = getName().getRawText();
if (propertyName != null) {
final String propertyValue = getValue().getRawText();
if (propertyValue != null) {
result = Collections.singletonMap(propertyName, propertyValue);
}
else {
String locValue = getLocation().getStringValue();
if (locValue != null) {
final File file = new File(locValue);
if (!file.isAbsolute()) {
final String baseDir = getContextAntProject().getProjectBasedirPath();
if (baseDir != null) {
locValue = PathUtil.getCanonicalPath(new File(baseDir, locValue).getPath());
}
}
result = Collections.singletonMap(propertyName, FileUtil.toSystemDependentName(locValue));
}
else {
// todo: process refid attrib if specified for the value
final String tagText = getXmlTag().getText();
result = Collections.singletonMap(propertyName, tagText);
}
}
}
else { // name attrib is not specified
final PsiFileSystemItem psiFile = getFile().getValue();
if (psiFile != null) {
final PropertiesFile file = toPropertiesFile(psiFile);
if (file != null) {
result = new HashMap<String, String>();
for (final IProperty property : file.getProperties()) {
result.put(property.getUnescapedKey(), property.getUnescapedValue());
}
}
}
else if (getEnvironment().getRawText() != null) {
String prefix = getEnvironment().getRawText();
if (!prefix.endsWith(".")) {
prefix += ".";
}
result = new HashMap<String, String>();
for (Map.Entry<String, String> entry : System.getenv().entrySet()) {
result.put(prefix + entry.getKey(), entry.getValue());
}
}
else {
// todo: consider Url attribute?
final String resource = getResource().getStringValue();
if (resource != null) {
final ClassLoader loader = getClassLoader();
if (loader != null) {
final InputStream stream = loader.getResourceAsStream(resource);
if (stream != null) {
try {
// todo: Remote file can be XmlPropertiesFile
final PropertiesFile propFile = (PropertiesFile)CustomAntElementsRegistry.loadContentAsFile(getXmlTag().getProject(), stream, StdFileTypes.PROPERTIES);
result = new HashMap<String, String>();
for (final IProperty property : propFile.getProperties()) {
result.put(property.getUnescapedKey(), property.getUnescapedValue());
}
}
catch (IOException ignored) {
}
}
}
}
}
}
return (myCachedProperties = result);
}
@Nullable
public String getPropertyPrefixValue() {
final GenericAttributeValue<String> prefixValue = getPrefix();
if (prefixValue == null) {
return null;
}
// prefix is only valid when loading from an url, file or resource
final boolean prefixIsApplicable = (getName().getRawText() == null) && (getUrl().getRawText() != null || getFile().getRawText() != null || getResource().getRawText() != null);
if (!prefixIsApplicable) {
return null;
}
final String prefix = prefixValue.getRawText();
if (prefix != null && !prefix.endsWith(".")) {
return prefix + ".";
}
return prefix;
}
@Nullable
private ClassLoader getClassLoader() {
ClassLoader loader = myCachedLoader;
if (loader == null) {
myCachedLoader = loader = CustomAntElementsRegistry.createClassLoader(CustomAntElementsRegistry.collectUrls(this), getContextAntProject());
}
return loader;
}
@Nullable
public PropertiesFile getPropertiesFile() {
return toPropertiesFile(getFile().getValue());
}
@Nullable
private static PropertiesFile toPropertiesFile(@Nullable final PsiFileSystemItem item) {
if (item instanceof PropertiesFile) {
return (PropertiesFile)item;
}
// Sometimes XmlPropertiesFile is just XmlFile, sao we should ask PropertiesImplUtil about that.
return item instanceof PsiFile? PropertiesImplUtil.getPropertiesFile(((PsiFile)item)) : null;
}
}