david_williams | 49d24fb | 2005-04-08 21:16:59 +0000 | [diff] [blame] | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2001, 2004 IBM Corporation and others. |
| 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the Eclipse Public License v1.0 |
| 5 | * which accompanies this distribution, and is available at |
| 6 | * http://www.eclipse.org/legal/epl-v10.html |
| 7 | * |
| 8 | * Contributors: |
| 9 | * IBM Corporation - initial API and implementation |
| 10 | *******************************************************************************/ |
david_williams | 96643dd | 2005-04-13 04:35:24 +0000 | [diff] [blame] | 11 | package org.eclipse.wst.html.internal.validation; |
pavery | e6107e6 | 2005-02-23 18:01:10 +0000 | [diff] [blame] | 12 | |
| 13 | import java.io.IOException; |
| 14 | import java.io.UnsupportedEncodingException; |
| 15 | |
| 16 | import org.eclipse.core.resources.IContainer; |
| 17 | import org.eclipse.core.resources.IFile; |
| 18 | import org.eclipse.core.resources.IProject; |
| 19 | import org.eclipse.core.resources.IResource; |
| 20 | import org.eclipse.core.resources.ResourcesPlugin; |
| 21 | import org.eclipse.core.runtime.CoreException; |
david_williams | e6ed732 | 2005-10-10 17:32:24 +0000 | [diff] [blame^] | 22 | import org.eclipse.core.runtime.IPath; |
pavery | e6107e6 | 2005-02-23 18:01:10 +0000 | [diff] [blame] | 23 | import org.eclipse.core.runtime.NullProgressMonitor; |
| 24 | import org.eclipse.core.runtime.OperationCanceledException; |
| 25 | import org.eclipse.core.runtime.Path; |
david_williams | e6ed732 | 2005-10-10 17:32:24 +0000 | [diff] [blame^] | 26 | import org.eclipse.core.runtime.Platform; |
| 27 | import org.eclipse.core.runtime.content.IContentType; |
| 28 | import org.eclipse.core.runtime.content.IContentTypeManager; |
nitind | e83b1a4 | 2005-06-22 21:22:20 +0000 | [diff] [blame] | 29 | import org.eclipse.osgi.util.NLS; |
david_williams | 5677702 | 2005-04-11 06:21:55 +0000 | [diff] [blame] | 30 | import org.eclipse.wst.html.core.internal.validate.HTMLValidationAdapterFactory; |
david_williams | 3a2ab2d | 2005-04-11 16:32:45 +0000 | [diff] [blame] | 31 | import org.eclipse.wst.html.ui.internal.HTMLUIMessages; |
david_williams | 4ad020f | 2005-04-18 08:00:30 +0000 | [diff] [blame] | 32 | import org.eclipse.wst.sse.core.internal.provisional.IModelManager; |
| 33 | import org.eclipse.wst.sse.core.internal.provisional.INodeAdapterFactory; |
| 34 | import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel; |
| 35 | import org.eclipse.wst.sse.core.internal.provisional.StructuredModelManager; |
david_williams | 2aecf08 | 2005-04-13 05:03:21 +0000 | [diff] [blame] | 36 | import org.eclipse.wst.sse.core.internal.util.URIResolver; |
david_williams | 3bcfe39 | 2005-04-13 04:49:36 +0000 | [diff] [blame] | 37 | import org.eclipse.wst.sse.core.internal.validate.ValidationAdapter; |
vbhadrir | 0b14da3 | 2005-04-18 15:40:15 +0000 | [diff] [blame] | 38 | import org.eclipse.wst.validation.internal.core.Message; |
vbhadrir | 271d28a | 2005-04-12 19:36:05 +0000 | [diff] [blame] | 39 | import org.eclipse.wst.validation.internal.operations.IWorkbenchContext; |
pavery | e6107e6 | 2005-02-23 18:01:10 +0000 | [diff] [blame] | 40 | import org.eclipse.wst.validation.internal.operations.WorkbenchReporter; |
david_williams | 49d24fb | 2005-04-08 21:16:59 +0000 | [diff] [blame] | 41 | import org.eclipse.wst.validation.internal.provisional.core.IMessage; |
| 42 | import org.eclipse.wst.validation.internal.provisional.core.IReporter; |
| 43 | import org.eclipse.wst.validation.internal.provisional.core.IValidationContext; |
| 44 | import org.eclipse.wst.validation.internal.provisional.core.IValidator; |
david_williams | 646a5e2 | 2005-04-02 07:16:27 +0000 | [diff] [blame] | 45 | import org.eclipse.wst.xml.core.internal.document.DocumentTypeAdapter; |
david_williams | 4ad020f | 2005-04-18 08:00:30 +0000 | [diff] [blame] | 46 | import org.eclipse.wst.xml.core.internal.provisional.document.IDOMDocument; |
| 47 | import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel; |
pavery | e6107e6 | 2005-02-23 18:01:10 +0000 | [diff] [blame] | 48 | |
| 49 | public class HTMLValidator implements IValidator { |
david_williams | e6ed732 | 2005-10-10 17:32:24 +0000 | [diff] [blame^] | 50 | private static final String ORG_ECLIPSE_JST_JSP_CORE_JSPSOURCE = "org.eclipse.jst.jsp.core.jspsource"; |
| 51 | private static final String ORG_ECLIPSE_WST_HTML_CORE_HTMLSOURCE = "org.eclipse.wst.html.core.htmlsource"; |
| 52 | |
nitind | 165498a | 2005-07-12 18:47:49 +0000 | [diff] [blame] | 53 | static boolean shouldValidate(IFile file) { |
| 54 | IResource resource = file; |
| 55 | do { |
| 56 | if (resource.isDerived() || resource.isTeamPrivateMember() || !resource.isAccessible() || (resource.getName().charAt(0) == '.' && resource.getType() == IResource.FOLDER)) { |
| 57 | return false; |
| 58 | } |
| 59 | resource = resource.getParent(); |
| 60 | } |
| 61 | while ((resource.getType() & IResource.PROJECT) == 0); |
| 62 | return true; |
| 63 | } |
| 64 | |
pavery | e6107e6 | 2005-02-23 18:01:10 +0000 | [diff] [blame] | 65 | public HTMLValidator() { |
| 66 | super(); |
| 67 | } |
| 68 | |
| 69 | /** |
| 70 | */ |
| 71 | public void cleanup(IReporter reporter) { |
| 72 | // nothing to do |
| 73 | } |
| 74 | |
| 75 | /** |
| 76 | */ |
david_williams | c39caaf | 2005-04-05 06:07:16 +0000 | [diff] [blame] | 77 | protected IDOMModel getModel(IProject project, IFile file) { |
pavery | e6107e6 | 2005-02-23 18:01:10 +0000 | [diff] [blame] | 78 | if (project == null || file == null) |
| 79 | return null; |
| 80 | if (!file.exists()) |
| 81 | return null; |
| 82 | if (!canHandle(file)) |
| 83 | return null; |
| 84 | |
| 85 | IStructuredModel model = null; |
| 86 | IModelManager manager = StructuredModelManager.getModelManager(); |
| 87 | |
| 88 | try { |
| 89 | try { |
| 90 | model = manager.getModelForRead(file); |
| 91 | } |
| 92 | catch (UnsupportedEncodingException ex) { |
david_williams | 49d24fb | 2005-04-08 21:16:59 +0000 | [diff] [blame] | 93 | // retry ignoring META charset for invalid META charset |
| 94 | // specification |
pavery | e6107e6 | 2005-02-23 18:01:10 +0000 | [diff] [blame] | 95 | // recreate input stream, because it is already partially read |
| 96 | model = manager.getModelForRead(file, new String(), null); |
| 97 | } |
| 98 | } |
| 99 | catch (UnsupportedEncodingException ex) { |
| 100 | } |
| 101 | catch (IOException ex) { |
| 102 | } |
| 103 | catch (CoreException ex) { |
| 104 | } |
| 105 | |
| 106 | if (model == null) |
| 107 | return null; |
david_williams | c39caaf | 2005-04-05 06:07:16 +0000 | [diff] [blame] | 108 | if (!(model instanceof IDOMModel)) { |
pavery | e6107e6 | 2005-02-23 18:01:10 +0000 | [diff] [blame] | 109 | releaseModel(model); |
| 110 | return null; |
| 111 | } |
david_williams | c39caaf | 2005-04-05 06:07:16 +0000 | [diff] [blame] | 112 | return (IDOMModel) model; |
pavery | e6107e6 | 2005-02-23 18:01:10 +0000 | [diff] [blame] | 113 | } |
| 114 | |
| 115 | /** |
| 116 | */ |
david_williams | c39caaf | 2005-04-05 06:07:16 +0000 | [diff] [blame] | 117 | protected HTMLValidationReporter getReporter(IReporter reporter, IFile file, IDOMModel model) { |
pavery | e6107e6 | 2005-02-23 18:01:10 +0000 | [diff] [blame] | 118 | return new HTMLValidationReporter(this, reporter, file, model); |
| 119 | } |
| 120 | |
| 121 | /** |
| 122 | * Check file extension to validate |
| 123 | */ |
| 124 | private boolean canHandle(IFile file) { |
david_williams | e6ed732 | 2005-10-10 17:32:24 +0000 | [diff] [blame^] | 125 | boolean result = false; |
| 126 | if (file != null) { |
| 127 | try { |
| 128 | IContentTypeManager contentTypeManager = Platform.getContentTypeManager(); |
| 129 | |
| 130 | IContentType fileContentType = file.getContentDescription().getContentType(); |
| 131 | |
| 132 | IContentType htmlContentType = contentTypeManager.getContentType(ORG_ECLIPSE_WST_HTML_CORE_HTMLSOURCE); |
| 133 | if (htmlContentType != null) { |
| 134 | if (fileContentType.isKindOf(htmlContentType)) { |
| 135 | result = true; |
| 136 | } |
| 137 | else { |
| 138 | // ISSUE: here's a little "backwards" dependancy. |
| 139 | // there should be a "JSPEMBEDDEDHTML validator" |
| 140 | // contributed by JSP plugin. |
| 141 | IContentType jspContentType = contentTypeManager.getContentType(ORG_ECLIPSE_JST_JSP_CORE_JSPSOURCE); |
| 142 | if (jspContentType != null) { |
| 143 | result = fileContentType.isKindOf(jspContentType); |
| 144 | } |
| 145 | } |
| 146 | } |
| 147 | } |
| 148 | catch (CoreException e) { |
| 149 | // should be rare, but will ignore to avoid logging "encoding |
| 150 | // exceptions" and the like here. |
| 151 | // Logger.logException(e); |
| 152 | } |
| 153 | } |
| 154 | return result; |
pavery | e6107e6 | 2005-02-23 18:01:10 +0000 | [diff] [blame] | 155 | } |
| 156 | |
| 157 | /** |
| 158 | */ |
david_williams | c39caaf | 2005-04-05 06:07:16 +0000 | [diff] [blame] | 159 | private boolean hasHTMLFeature(IDOMDocument document) { |
pavery | e6107e6 | 2005-02-23 18:01:10 +0000 | [diff] [blame] | 160 | DocumentTypeAdapter adapter = (DocumentTypeAdapter) document.getAdapterFor(DocumentTypeAdapter.class); |
| 161 | if (adapter == null) |
| 162 | return false; |
| 163 | return adapter.hasFeature("HTML");//$NON-NLS-1$ |
| 164 | } |
| 165 | |
| 166 | /** |
| 167 | */ |
| 168 | protected void releaseModel(IStructuredModel model) { |
| 169 | if (model != null) |
| 170 | model.releaseFromRead(); |
| 171 | } |
| 172 | |
| 173 | /** |
| 174 | */ |
vbhadrir | 271d28a | 2005-04-12 19:36:05 +0000 | [diff] [blame] | 175 | public void validate(IValidationContext helper, IReporter reporter) { |
pavery | e6107e6 | 2005-02-23 18:01:10 +0000 | [diff] [blame] | 176 | if (helper == null) |
| 177 | return; |
| 178 | if ((reporter != null) && (reporter.isCancelled() == true)) { |
| 179 | throw new OperationCanceledException(); |
| 180 | } |
vbhadrir | 271d28a | 2005-04-12 19:36:05 +0000 | [diff] [blame] | 181 | String[] deltaArray = helper.getURIs(); |
pavery | e6107e6 | 2005-02-23 18:01:10 +0000 | [diff] [blame] | 182 | if (deltaArray != null && deltaArray.length > 0) { |
vbhadrir | 271d28a | 2005-04-12 19:36:05 +0000 | [diff] [blame] | 183 | validateDelta(helper, reporter); |
pavery | e6107e6 | 2005-02-23 18:01:10 +0000 | [diff] [blame] | 184 | } |
| 185 | else { |
vbhadrir | 271d28a | 2005-04-12 19:36:05 +0000 | [diff] [blame] | 186 | validateFull(helper, reporter); |
pavery | e6107e6 | 2005-02-23 18:01:10 +0000 | [diff] [blame] | 187 | } |
| 188 | } |
| 189 | |
| 190 | /** |
| 191 | */ |
david_williams | c39caaf | 2005-04-05 06:07:16 +0000 | [diff] [blame] | 192 | protected HTMLValidationResult validate(IDOMModel model, IFile file) { |
pavery | e6107e6 | 2005-02-23 18:01:10 +0000 | [diff] [blame] | 193 | IProject prj = null; |
| 194 | if (file != null) { |
| 195 | prj = file.getProject(); |
| 196 | } |
david_williams | 49d24fb | 2005-04-08 21:16:59 +0000 | [diff] [blame] | 197 | if ((prj == null) && (model != null)) { |
pavery | e6107e6 | 2005-02-23 18:01:10 +0000 | [diff] [blame] | 198 | URIResolver res = model.getResolver(); |
| 199 | if (res != null) { |
| 200 | prj = res.getProject(); |
| 201 | } |
| 202 | } |
| 203 | final WorkbenchReporter reporter = new WorkbenchReporter(prj, new NullProgressMonitor()); |
david_williams | 49d24fb | 2005-04-08 21:16:59 +0000 | [diff] [blame] | 204 | return validate(reporter, file, model); |
pavery | e6107e6 | 2005-02-23 18:01:10 +0000 | [diff] [blame] | 205 | } |
| 206 | |
| 207 | /** |
| 208 | */ |
david_williams | c39caaf | 2005-04-05 06:07:16 +0000 | [diff] [blame] | 209 | private HTMLValidationResult validate(IReporter reporter, IFile file, IDOMModel model) { |
pavery | e6107e6 | 2005-02-23 18:01:10 +0000 | [diff] [blame] | 210 | if (file == null || model == null) |
| 211 | return null; // error |
david_williams | c39caaf | 2005-04-05 06:07:16 +0000 | [diff] [blame] | 212 | IDOMDocument document = model.getDocument(); |
pavery | e6107e6 | 2005-02-23 18:01:10 +0000 | [diff] [blame] | 213 | if (document == null) |
| 214 | return null; // error |
| 215 | if (!hasHTMLFeature(document)) |
| 216 | return null; // ignore |
| 217 | |
david_williams | 285ee2d | 2005-04-10 18:21:21 +0000 | [diff] [blame] | 218 | INodeAdapterFactory factory = HTMLValidationAdapterFactory.getInstance(); |
pavery | e6107e6 | 2005-02-23 18:01:10 +0000 | [diff] [blame] | 219 | ValidationAdapter adapter = (ValidationAdapter) factory.adapt(document); |
| 220 | if (adapter == null) |
| 221 | return null; // error |
| 222 | |
| 223 | HTMLValidationReporter rep = getReporter(reporter, file, model); |
| 224 | rep.clear(); |
| 225 | adapter.setReporter(rep); |
| 226 | if (reporter != null) { |
david_williams | e6ed732 | 2005-10-10 17:32:24 +0000 | [diff] [blame^] | 227 | String fileName = ""; |
| 228 | IPath filePath = file.getFullPath(); |
| 229 | if (filePath != null) { |
| 230 | fileName = filePath.toString(); |
| 231 | } |
| 232 | String args[] = new String[]{fileName}; |
david_williams | 49d24fb | 2005-04-08 21:16:59 +0000 | [diff] [blame] | 233 | |
| 234 | // Message mess = new Message("HTMLValidation", //$NON-NLS-1$ |
| 235 | // SeverityEnum.LOW_SEVERITY, |
| 236 | // "MESSAGE_HTML_VALIDATION_MESSAGE_UI_", //$NON-NLS-1$ |
| 237 | // args); |
nitind | e83b1a4 | 2005-06-22 21:22:20 +0000 | [diff] [blame] | 238 | Message mess = new LocalizedMessage(IMessage.LOW_SEVERITY, NLS.bind(HTMLUIMessages.MESSAGE_HTML_VALIDATION_MESSAGE_UI_, args)); |
pavery | e6107e6 | 2005-02-23 18:01:10 +0000 | [diff] [blame] | 239 | mess.setParams(args); |
| 240 | reporter.displaySubtask(this, mess); |
| 241 | } |
| 242 | adapter.validate(document); |
| 243 | return rep.getResult(); |
| 244 | } |
| 245 | |
| 246 | /** |
| 247 | */ |
david_williams | 4327167 | 2005-04-01 05:19:26 +0000 | [diff] [blame] | 248 | private void validateContainer(IValidationContext helper, IReporter reporter, IContainer container) { |
pavery | e6107e6 | 2005-02-23 18:01:10 +0000 | [diff] [blame] | 249 | try { |
| 250 | IResource[] resourceArray = container.members(false); |
| 251 | for (int i = 0; i < resourceArray.length; i++) { |
| 252 | IResource resource = resourceArray[i]; |
| 253 | if (resource == null) |
| 254 | continue; |
| 255 | if (resource instanceof IFile) { |
| 256 | validateFile(helper, reporter, (IFile) resource); |
| 257 | } |
| 258 | else if (resource instanceof IContainer) { |
| 259 | validateContainer(helper, reporter, (IContainer) resource); |
| 260 | } |
| 261 | } |
| 262 | } |
| 263 | catch (CoreException ex) { |
| 264 | } |
| 265 | } |
| 266 | |
| 267 | /** |
| 268 | */ |
vbhadrir | 271d28a | 2005-04-12 19:36:05 +0000 | [diff] [blame] | 269 | private void validateDelta(IValidationContext helper, IReporter reporter) { |
| 270 | String[] deltaArray = helper.getURIs(); |
pavery | e6107e6 | 2005-02-23 18:01:10 +0000 | [diff] [blame] | 271 | for (int i = 0; i < deltaArray.length; i++) { |
vbhadrir | 271d28a | 2005-04-12 19:36:05 +0000 | [diff] [blame] | 272 | String delta = deltaArray[i]; |
| 273 | if (delta == null) |
pavery | e6107e6 | 2005-02-23 18:01:10 +0000 | [diff] [blame] | 274 | continue; |
| 275 | IResource resource = getResource(delta); |
| 276 | if (resource == null || !(resource instanceof IFile)) |
| 277 | continue; |
| 278 | validateFile(helper, reporter, (IFile) resource); |
| 279 | } |
| 280 | } |
| 281 | |
| 282 | /** |
| 283 | */ |
david_williams | 4327167 | 2005-04-01 05:19:26 +0000 | [diff] [blame] | 284 | private void validateFile(IValidationContext helper, IReporter reporter, IFile file) { |
pavery | e6107e6 | 2005-02-23 18:01:10 +0000 | [diff] [blame] | 285 | if ((reporter != null) && (reporter.isCancelled() == true)) { |
| 286 | throw new OperationCanceledException(); |
| 287 | } |
nitind | 165498a | 2005-07-12 18:47:49 +0000 | [diff] [blame] | 288 | if (!shouldValidate(file)) { |
| 289 | return; |
| 290 | } |
david_williams | c39caaf | 2005-04-05 06:07:16 +0000 | [diff] [blame] | 291 | IDOMModel model = getModel(file.getProject(), file); |
pavery | e6107e6 | 2005-02-23 18:01:10 +0000 | [diff] [blame] | 292 | if (model == null) |
| 293 | return; |
| 294 | |
| 295 | try { |
| 296 | validate(reporter, file, model); |
| 297 | } |
| 298 | finally { |
| 299 | releaseModel(model); |
| 300 | } |
| 301 | } |
| 302 | |
| 303 | /** |
| 304 | */ |
vbhadrir | 271d28a | 2005-04-12 19:36:05 +0000 | [diff] [blame] | 305 | private void validateFull(IValidationContext helper, IReporter reporter) { |
pavery | e6107e6 | 2005-02-23 18:01:10 +0000 | [diff] [blame] | 306 | IProject project = null; |
vbhadrir | 271d28a | 2005-04-12 19:36:05 +0000 | [diff] [blame] | 307 | String[] fileDelta = helper.getURIs(); |
| 308 | if (helper instanceof IWorkbenchContext) { |
| 309 | IWorkbenchContext wbHelper = (IWorkbenchContext) helper; |
pavery | e6107e6 | 2005-02-23 18:01:10 +0000 | [diff] [blame] | 310 | project = wbHelper.getProject(); |
| 311 | } |
| 312 | else { |
| 313 | // won't work for project validation (b/c nothing in file delta) |
| 314 | project = getResource(fileDelta[0]).getProject(); |
| 315 | } |
| 316 | if (project == null) |
| 317 | return; |
| 318 | validateContainer(helper, reporter, project); |
| 319 | } |
| 320 | |
david_williams | 49d24fb | 2005-04-08 21:16:59 +0000 | [diff] [blame] | 321 | /* |
pavery | e6107e6 | 2005-02-23 18:01:10 +0000 | [diff] [blame] | 322 | * added to get rid or dependency on IWorkbenchHelper |
david_williams | 49d24fb | 2005-04-08 21:16:59 +0000 | [diff] [blame] | 323 | * |
pavery | e6107e6 | 2005-02-23 18:01:10 +0000 | [diff] [blame] | 324 | */ |
vbhadrir | 271d28a | 2005-04-12 19:36:05 +0000 | [diff] [blame] | 325 | public IResource getResource(String delta) { |
david_williams | e6ed732 | 2005-10-10 17:32:24 +0000 | [diff] [blame^] | 326 | return ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(delta)); |
pavery | e6107e6 | 2005-02-23 18:01:10 +0000 | [diff] [blame] | 327 | } |
| 328 | } |