/*
* 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 org.napile.idea.thermit.dom;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import com.intellij.lang.properties.IProperty;
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.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;
/**
* @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());
}
if(psiFile instanceof PropertiesFile)
{
final IProperty property = ((PropertiesFile) psiFile).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)
{
if(psiFile instanceof PropertiesFile)
{
result = new HashMap<String, String>();
for(final IProperty property : ((PropertiesFile) psiFile).getProperties())
{
result.put(property.getUnescapedKey(), property.getValue());
}
}
}
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
{
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.getValue());
}
}
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;
}
}