/*******************************************************************************
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*
*******************************************************************************/
package com.liferay.ide.project.core;
import com.liferay.ide.core.IWebProject;
import com.liferay.ide.core.LiferayCore;
import com.liferay.ide.core.util.NodeUtil;
import com.liferay.ide.core.util.StringPool;
import java.io.IOException;
import java.io.InputStream;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.preferences.IPreferencesService;
import org.eclipse.core.runtime.preferences.IScopeContext;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.ITypeHierarchy;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.osgi.util.NLS;
import org.eclipse.wst.sse.core.StructuredModelManager;
import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
import org.eclipse.wst.sse.core.internal.validate.ValidationMessage;
import org.eclipse.wst.validation.AbstractValidator;
import org.eclipse.wst.validation.ValidationEvent;
import org.eclipse.wst.validation.internal.provisional.core.IMessage;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMDocument;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMNode;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* @author Greg Amerson
*/
@SuppressWarnings( "restriction" )
public abstract class BaseValidator extends AbstractValidator
{
public static final String MESSAGE_CLASS_INCORRECT_HIERARCHY = Msgs.typeHierarchyIncorrect;
public static final String MESSAGE_CLASS_NOT_FOUND = Msgs.classNotFound;
protected IPreferencesService fPreferencesService = Platform.getPreferencesService();
public BaseValidator()
{
super();
}
@SuppressWarnings( "unchecked" )
protected Map<String, Object>[] checkAllClassElements(
Map<String, String> map, IJavaProject javaProject, IFile liferayDescriptorXml,
String classExistPreferenceKey, String classHierarchyPreferenceKey, IScopeContext[] preferenceScopes,
String preferenceNodeQualifier, List<Map<String, Object>> problems ) throws CoreException
{
IStructuredModel liferayDescriptorXmlModel = null;
IDOMDocument liferayDescriptorXmlDocument = null;
try
{
liferayDescriptorXmlModel =
StructuredModelManager.getModelManager().getModelForRead( liferayDescriptorXml );
if( liferayDescriptorXmlModel != null && liferayDescriptorXmlModel instanceof IDOMModel && map != null )
{
liferayDescriptorXmlDocument = ( (IDOMModel) liferayDescriptorXmlModel ).getDocument();
for( String elementName : map.keySet() )
{
checkClassElements(
liferayDescriptorXmlDocument, javaProject, elementName, preferenceNodeQualifier,
preferenceScopes, classExistPreferenceKey, classHierarchyPreferenceKey, problems,
map.get( elementName ) );
}
}
}
catch( IOException e )
{
ProjectCore.logError( e );
}
finally
{
if( liferayDescriptorXmlModel != null )
{
liferayDescriptorXmlModel.releaseFromRead();
}
}
Map<String, Object>[] retval = new Map[problems.size()];
return (Map<String, Object>[]) problems.toArray( retval );
}
protected Map<String, Object> checkClass(
IJavaProject javaProject, Node classSpecifier, String preferenceNodeQualifier,
IScopeContext[] preferenceScopes, String classExistPreferenceKey, String classHierarchyPreferenceKey,
String superTypeNames )
{
String className = NodeUtil.getTextContent( classSpecifier );
if( className != null && className.length() > 0 )
{
IType type = null;
try
{
type = javaProject.findType( className );
if( type == null || !type.exists() || className.startsWith( "." ) )
{
final String msg =
MessageFormat.format( MESSAGE_CLASS_NOT_FOUND, new Object[] { className } );
return createMarkerValues(
preferenceNodeQualifier, preferenceScopes, classExistPreferenceKey,
(IDOMNode) classSpecifier, msg );
}
else if( superTypeNames != null )
{
boolean typeFound = false;
final String[] superTypes = superTypeNames.split( StringPool.COMMA );
for( String superType : superTypes )
{
try
{
IType checkType = javaProject.findType( superType.trim() );
if( checkType != null )
{
ITypeHierarchy supertypeHierarchy = type.newSupertypeHierarchy( null );
if( supertypeHierarchy.contains( checkType ) )
{
typeFound = true;
break;
}
}
}
catch( JavaModelException e )
{
ProjectCore.logError( e );
}
}
if( typeFound == false )
{
String msg =
MessageFormat.format( MESSAGE_CLASS_INCORRECT_HIERARCHY, className, superTypeNames );
if( superTypeNames.contains( StringPool.COMMA ) )
{
msg = msg.replaceAll( Msgs.typeLabel, Msgs.possibleTypes );
}
return createMarkerValues(
preferenceNodeQualifier, preferenceScopes, classHierarchyPreferenceKey,
(IDOMNode) classSpecifier, msg );
}
}
}
catch( JavaModelException e )
{
return null;
}
}
return null;
}
protected void checkClassElements(
IDOMDocument document, IJavaProject javaProject, String classElement, String preferenceNodeQualifier,
IScopeContext[] preferenceScopes, String classExistPreferenceKey, String classHierarchyPreferenceKey,
List<Map<String, Object>> problems, String superTypeNames )
{
final NodeList classes = document.getElementsByTagName( classElement );
for( int i = 0; i < classes.getLength(); i++ )
{
final Node item = classes.item( i );
final Map<String, Object> problem =
checkClass(
javaProject, item, preferenceNodeQualifier, preferenceScopes, classExistPreferenceKey,
classHierarchyPreferenceKey, superTypeNames );
if( problem != null )
{
problems.add( problem );
}
}
}
protected void checkDocrootElement(
IDOMDocument document, String element, IProject project, String preferenceNodeQualifier,
IScopeContext[] preferenceScopes, String liferayPluginValidationType, String messageKey,
List<Map<String, Object>> problems )
{
NodeList elements = document.getElementsByTagName( element );
for( int i = 0; i < elements.getLength(); i++ )
{
Node item = elements.item( i );
Map<String, Object> problem =
checkDocrootResource(
item, project, preferenceNodeQualifier, preferenceScopes, liferayPluginValidationType,
messageKey );
if( problem != null )
{
problems.add( problem );
}
}
}
protected Map<String, Object> checkDocrootResource(
Node resourceSpecifier, IProject project, String preferenceNodeQualifier, IScopeContext[] preferenceScopes,
String preferenceKey, String errorMessage )
{
String resourceValue = NodeUtil.getTextContent( resourceSpecifier );
if( resourceValue != null && resourceValue.length() > 0 )
{
final IWebProject webproject = LiferayCore.create( IWebProject.class, project );
if( webproject != null )
{
// IDE-110 IDE-648
final IResource resource = webproject.findDocrootResource( new Path( resourceValue ) );
if( resource == null || !resource.exists() )
{
String msg = MessageFormat.format( errorMessage, new Object[] { resourceValue } );
return createMarkerValues(
preferenceNodeQualifier, preferenceScopes, preferenceKey, (IDOMNode) resourceSpecifier,
msg );
}
}
}
return null;
}
protected Map<String, Object> createMarkerValues(
String qualifier, IScopeContext[] preferenceScopes, String preferenceKey, IDOMNode domNode, String message )
{
Object severity = getMessageSeverity( qualifier, preferenceScopes, preferenceKey );
if( severity == null )
{
return null;
}
Map<String, Object> markerValues = new HashMap<String, Object>();
setMarkerValues( markerValues, severity, domNode, message );
return markerValues;
}
protected Map<String, String> getAllClasseElements( String liferayDescriptorClassElementsProperties )
{
Map<String, String> map = new HashMap<String, String>();
Properties p = new Properties();
InputStream resource = null;
try
{
resource =
this.getClass().getClassLoader().getResourceAsStream( liferayDescriptorClassElementsProperties );
p.load( resource );
for( Object key : p.keySet() )
{
String elementName = key.toString();
String typeNames = p.get( key ).toString();
map.put( elementName, typeNames );
}
}
catch( IOException e )
{
ProjectCore.logError( e );
}
finally
{
if( resource != null )
{
try
{
resource.close();
}
catch( IOException e )
{
}
}
}
return map;
}
protected IPath[] getSourceEntries( IJavaProject javaProject )
{
List<IPath> paths = new ArrayList<IPath>();
try
{
final IClasspathEntry[] classpathEntries = javaProject.getResolvedClasspath( true );
for( IClasspathEntry entry : classpathEntries )
{
if( entry.getEntryKind() == IClasspathEntry.CPE_SOURCE )
{
paths.add( entry.getPath() );
}
}
}
catch( JavaModelException e )
{
ProjectCore.logError( "Error resolving classpath.", e );
}
return paths.toArray( new IPath[0] );
}
protected Integer getMessageSeverity( String qualifier, IScopeContext[] preferenceScopes, String key )
{
int sev = fPreferencesService.getInt( qualifier, key, IMessage.NORMAL_SEVERITY, preferenceScopes );
switch( sev )
{
case ValidationMessage.ERROR:
return new Integer( IMarker.SEVERITY_ERROR );
case ValidationMessage.WARNING:
return new Integer( IMarker.SEVERITY_WARNING );
case ValidationMessage.INFORMATION:
return new Integer( IMarker.SEVERITY_INFO );
case ValidationMessage.IGNORE:
return null;
}
return new Integer( IMarker.SEVERITY_WARNING );
}
protected void setMarkerValues(
Map<String, Object> markerValues, Object severity, IDOMNode domNode, String message )
{
markerValues.put( IMarker.SEVERITY, severity );
int start = domNode.getStartOffset();
if( domNode.getStartStructuredDocumentRegion() != null && domNode.getEndStructuredDocumentRegion() != null )
{
start = domNode.getStartStructuredDocumentRegion().getEndOffset();
}
int end = domNode.getEndOffset();
if( domNode.getStartStructuredDocumentRegion() != null &&
domNode.getEndStructuredDocumentRegion() != null )
{
end = domNode.getEndStructuredDocumentRegion().getStartOffset();
}
int line = domNode.getStructuredDocument().getLineOfOffset( start );
markerValues.put( IMarker.CHAR_START, new Integer( start ) );
markerValues.put( IMarker.CHAR_END, new Integer( end ) );
markerValues.put( IMarker.LINE_NUMBER, new Integer( line + 1 ) );
markerValues.put( IMarker.MESSAGE, message );
}
@Override
public boolean shouldClearMarkers( ValidationEvent event )
{
return true;
}
private static class Msgs extends NLS
{
public static String classNotFound;
public static String possibleTypes;
public static String typeLabel;
public static String typeHierarchyIncorrect;
static
{
initializeMessages( BaseValidator.class.getName(), Msgs.class );
}
}
}