/* * ==================================================================== * * The ObjectStyle Group Software License, Version 1.0 * * Copyright (c) 2005 The ObjectStyle Group and individual authors of the * software. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: 1. * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. 2. Redistributions in * binary form must reproduce the above copyright notice, this list of * conditions and the following disclaimer in the documentation and/or other * materials provided with the distribution. 3. The end-user documentation * included with the redistribution, if any, must include the following * acknowlegement: "This product includes software developed by the ObjectStyle * Group (http://objectstyle.org/)." Alternately, this acknowlegement may * appear in the software itself, if and wherever such third-party * acknowlegements normally appear. 4. The names "ObjectStyle Group" and * "Cayenne" must not be used to endorse or promote products derived from this * software without prior written permission. For written permission, please * contact andrus@objectstyle.org. 5. Products derived from this software may * not be called "ObjectStyle" nor may "ObjectStyle" appear in their names * without prior written permission of the ObjectStyle Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * OBJECTSTYLE GROUP OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many individuals * on behalf of the ObjectStyle Group. For more information on the ObjectStyle * Group, please see <http://objectstyle.org/> . * */ package org.objectstyle.wolips.bindings.wod; import java.io.IOException; import java.io.Writer; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.core.runtime.CoreException; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.Position; import org.objectstyle.wolips.bindings.Activator; import org.objectstyle.wolips.bindings.api.ApiModelException; import org.objectstyle.wolips.bindings.api.ApiUtils; import org.objectstyle.wolips.bindings.api.Binding; import org.objectstyle.wolips.bindings.api.IApiBinding; import org.objectstyle.wolips.bindings.api.Validation; import org.objectstyle.wolips.bindings.api.Wo; import org.objectstyle.wolips.bindings.preferences.PreferenceConstants; import org.objectstyle.wolips.bindings.utils.BindingReflectionUtils; /** * @author mschrag */ public abstract class AbstractWodElement implements IWodElement, Comparable<IWodElement> { private List<IWodBinding> _bindings; private boolean _inline; private String _tagName; private boolean _inherited; public AbstractWodElement() { _bindings = new LinkedList<IWodBinding>(); } public void setInherited(boolean inherited) { _inherited = inherited; } public boolean isInherited() { return _inherited; } public boolean isInline() { return _inline; } public void setInline(boolean inline) { _inline = inline; } public void addBinding(IWodBinding binding) { _bindings.add(binding); } public void removeBinding(IWodBinding binding) { _bindings.remove(binding); } public List<IWodBinding> getBindings() { return _bindings; } public IWodBinding getBindingNamed(String name) { IWodBinding matchingBinding = null; Iterator<IWodBinding> wodBindingsIter = _bindings.iterator(); while (matchingBinding == null && wodBindingsIter.hasNext()) { IWodBinding wodBinding = wodBindingsIter.next(); if (name.equals(wodBinding.getName())) { matchingBinding = wodBinding; } } return matchingBinding; } public String getBindingValue(String name) { String value = null; IWodBinding binding = getBindingNamed(name); if (binding != null) { value = binding.getValue(); } return value; } public Map<String, String> getBindingsMap() { Map<String, String> bindingsMap = new HashMap<String, String>(); Iterator<IWodBinding> bindingsIter = _bindings.iterator(); while (bindingsIter.hasNext()) { IWodBinding binding = bindingsIter.next(); bindingsMap.put(binding.getName(), binding.getValue()); } return bindingsMap; } public int compareTo(IWodElement otherElement) { String otherName = otherElement.getElementName(); int comparison = getElementName().compareTo(otherName); return comparison; } public void writeWodFormat(Writer writer, boolean alphabetize) throws IOException { List<IWodBinding> bindings = getBindings(); if (alphabetize) { bindings = new LinkedList<IWodBinding>(bindings); Collections.sort(bindings, new WodBindingComparator()); } writer.write(getElementName()); writer.write(" : "); writer.write(getElementType()); writer.write(" {"); writer.write("\n"); for (IWodBinding binding : bindings) { binding.writeWodFormat(writer); writer.write("\n"); } writer.write("}\n"); } public void writeInlineFormat(Writer writer, String content, boolean alphabetize, String bindingPrefix, String bindingSuffix) throws IOException { writeInlineFormat(writer, content, alphabetize, true, true, true, bindingPrefix, bindingSuffix); } public void writeInlineFormat(Writer writer, String content, boolean alphabetize, boolean showOpenTag, boolean showContent, boolean showCloseTag, String bindingPrefix, String bindingSuffix) throws IOException { List<IWodBinding> bindings = getBindings(); if (alphabetize) { bindings = new LinkedList<IWodBinding>(bindings); Collections.sort(bindings, new WodBindingComparator()); } if (showOpenTag) { writer.write("<"); writer.write(getTagName()); for (IWodBinding binding : bindings) { binding.writeInlineFormat(writer, bindingPrefix, bindingSuffix); } if (content == null) { writer.write("/>"); } else { writer.write(">"); } } if (content != null) { if (showContent) { writer.write(content); } if (showCloseTag) { writer.write("</"); writer.write(getTagName()); writer.write(">"); } } } public void setTagName(String tagName) { _tagName = tagName; } public String getTagName() { String tagName; if (_tagName == null) { tagName = "tb:" + getElementType(); // "wo:" } else { tagName = _tagName; } return tagName; } public Wo getApi(IJavaProject javaProject, TypeCache cache) throws JavaModelException, ApiModelException { String elementTypeName = getElementType(); IType elementType = BindingReflectionUtils.findElementType(javaProject, elementTypeName, false, cache); Wo wo = ApiUtils.findApiModelWo(elementType, cache.getApiCache(javaProject)); return wo; } public IApiBinding[] getApiBindings(Wo api) { IApiBinding[] wodBindings = null; boolean apiFound = false; try { if (api != null) { apiFound = true; List<IApiBinding> visibleBindings = new LinkedList<IApiBinding>(); List<Binding> apiBindings = api.getBindings(); visibleBindings.addAll(apiBindings); for (IWodBinding wodBinding : getBindings()) { String bindingName = wodBinding.getName(); boolean wodBindingDefinedInApi = false; for (IApiBinding apiBinding : apiBindings) { if (apiBinding.getName().equals(bindingName)) { wodBindingDefinedInApi = true; break; } } if (!wodBindingDefinedInApi) { visibleBindings.add(wodBinding); } } wodBindings = visibleBindings.toArray(new IApiBinding[visibleBindings.size()]); } } catch (Throwable t) { Activator.getDefault().log("Failed to retrieve bindings for " + this + ".", t); } if (!apiFound) { List<IWodBinding> currentBindings = getBindings(); wodBindings = currentBindings.toArray(new IApiBinding[currentBindings.size()]); } return wodBindings; } public abstract int getLineNumber(); public void fillInProblems(IJavaProject javaProject, IType javaFileType, boolean checkBindingValues, List<WodProblem> problems, TypeCache typeCache, HtmlElementCache htmlCache) throws CoreException { String elementTypeName = getElementType(); String elementName = getElementName(); int lineNumber = getLineNumber(); String wodMissingComponentSeverity = Activator.getDefault().getPluginPreferences().getString(PreferenceConstants.WOD_MISSING_COMPONENT_SEVERITY_KEY); String unusedWodElementSeverity = Activator.getDefault().getPluginPreferences().getString(PreferenceConstants.UNUSED_WOD_ELEMENT_SEVERITY_KEY); if (!PreferenceConstants.IGNORE.equals(unusedWodElementSeverity) && !_inline && !htmlCache.containsElementNamed(elementName)) { problems.add(new WodElementProblem(this, "There is no element named '" + elementName + "' in your component HTML file", getElementNamePosition(), lineNumber, PreferenceConstants.WARNING.equals(unusedWodElementSeverity))); } String deprecationSeverity = Activator.getDefault().getPluginPreferences().getString(PreferenceConstants.DEPRECATED_BINDING_SEVERITY_KEY); if (!PreferenceConstants.IGNORE.equals(deprecationSeverity)) { IType elementType = BindingReflectionUtils.findElementType(javaProject, elementTypeName, false, typeCache); if (BindingReflectionUtils.memberIsDeprecated(elementType)) { problems.add(new WodElementDeprecationProblem(this, "The component named '" + elementTypeName + "' is deprecated.", getElementTypePosition(), lineNumber, PreferenceConstants.WARNING.equals(deprecationSeverity))); } } Wo wo = null; if (!PreferenceConstants.IGNORE.equals(wodMissingComponentSeverity)) { IType elementType = BindingReflectionUtils.findElementType(javaProject, elementTypeName, false, typeCache); if (elementType == null || (!elementType.getElementName().equals(elementTypeName) && !elementType.getFullyQualifiedName().equals(elementTypeName))) { problems.add(new WodElementProblem(this, "The class for '" + elementTypeName + "' is either missing or does not extend WOElement.", getElementTypePosition(), lineNumber, PreferenceConstants.WARNING.equals(wodMissingComponentSeverity))); } else { String wodApiProblemSeverity = Activator.getDefault().getPluginPreferences().getString(PreferenceConstants.WOD_API_PROBLEMS_SEVERITY_KEY); if (!PreferenceConstants.IGNORE.equals(wodApiProblemSeverity)) { try { wo = ApiUtils.findApiModelWo(elementType, typeCache.getApiCache(javaProject)); if (wo != null) { Map<String, String> bindingsMap = getBindingsMap(); List<Binding> bindings = wo.getBindings(); for (Binding binding : bindings) { String bindingName = binding.getName(); if (binding.isExplicitlyRequired() && !bindingsMap.containsKey(bindingName)) { problems.add(new ApiBindingValidationProblem(this, binding, getElementNamePosition(), lineNumber, PreferenceConstants.WARNING.equals(wodApiProblemSeverity))); } } List<Validation> failedValidations = wo.getFailedValidations(bindingsMap); for (Validation failedValidation : failedValidations) { problems.add(new ApiElementValidationProblem(this, failedValidation, getElementNamePosition(), lineNumber, PreferenceConstants.WARNING.equals(wodApiProblemSeverity))); } } } catch (Throwable e) { Activator.getDefault().log(e); } } } } Set<String> bindingNames = new HashSet<String>(); Iterator<IWodBinding> checkForDuplicateBindingsIter = getBindings().iterator(); while (checkForDuplicateBindingsIter.hasNext()) { IWodBinding binding = checkForDuplicateBindingsIter.next(); String bindingName = binding.getName(); if (bindingNames.contains(bindingName)) { problems.add(new WodBindingNameProblem(this, binding, bindingName, "Duplicate binding named '" + bindingName + "'", binding.getNamePosition(), binding.getLineNumber(), false)); } else { bindingNames.add(bindingName); } } JavaModelException javaModelException = null; if (checkBindingValues && javaFileType != null) { Iterator<IWodBinding> bindingsIter = getBindings().iterator(); while (bindingsIter.hasNext()) { IWodBinding binding = bindingsIter.next(); try { IApiBinding apiBinding = null; if (wo != null) { apiBinding = wo.getBinding(binding.getName()); } binding.fillInBindingProblems(this, apiBinding, javaProject, javaFileType, problems, typeCache, htmlCache); } catch (JavaModelException t) { javaModelException = t; Activator.getDefault().log("Failed to check wod binding values.", t); } catch (Throwable t) { Activator.getDefault().log("Failed to check wod binding values.", t); } } } if (javaModelException != null) { throw javaModelException; } } public boolean isWithin(IRegion region) { return getStartOffset() <= region.getOffset() && getEndOffset() > region.getOffset(); } public boolean isTypeWithin(IRegion region) { Position typePosition = getElementTypePosition(); return typePosition != null && typePosition.getOffset() <= region.getOffset() && typePosition.getOffset() + typePosition.getLength() > region.getOffset(); } @Override public String toString() { return "[" + getClass().getName() + ": elementName = " + getElementName() + "; elementType = " + getElementType() + "; bindings = " + _bindings + "]"; } }