001: /*
002: * File : $Source: /usr/local/cvs/opencms/src-modules/org/opencms/workplace/tools/content/check/CmsContentCheckProperty.java,v $
003: * Date : $Date: 2008-02-27 12:05:42 $
004: * Version: $Revision: 1.8 $
005: *
006: * This library is part of OpenCms -
007: * the Open Source Content Management System
008: *
009: * Copyright (c) 2002 - 2008 Alkacon Software GmbH (http://www.alkacon.com)
010: *
011: * This library is free software; you can redistribute it and/or
012: * modify it under the terms of the GNU Lesser General Public
013: * License as published by the Free Software Foundation; either
014: * version 2.1 of the License, or (at your option) any later version.
015: *
016: * This library is distributed in the hope that it will be useful,
017: * but WITHOUT ANY WARRANTY; without even the implied warranty of
018: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
019: * Lesser General Public License for more details.
020: *
021: * For further information about Alkacon Software GmbH, please see the
022: * company website: http://www.alkacon.com
023: *
024: * For further information about OpenCms, please see the
025: * project website: http://www.opencms.org
026: *
027: * You should have received a copy of the GNU Lesser General Public
028: * License along with this library; if not, write to the Free Software
029: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
030: */
031:
032: package org.opencms.workplace.tools.content.check;
033:
034: import org.opencms.file.CmsFile;
035: import org.opencms.file.CmsObject;
036: import org.opencms.file.CmsResource;
037: import org.opencms.main.CmsException;
038: import org.opencms.main.CmsLog;
039: import org.opencms.util.CmsStringUtil;
040: import org.opencms.xml.content.CmsXmlContent;
041: import org.opencms.xml.content.CmsXmlContentFactory;
042:
043: import java.util.ArrayList;
044: import java.util.List;
045: import java.util.Locale;
046: import java.util.regex.Pattern;
047:
048: import org.apache.commons.logging.Log;
049:
050: /**
051: * This implementation of the I_CmsContentCheck interface implements a check for
052: * resource properties.<p>
053: *
054: * The following items can be configured and checked:
055: * <ul>
056: * <li>Property not set</li>
057: * <li>Property value contains filename</li>
058: * <li>Property value is shorter than a minimum size</li>
059: * <li>Property value contains a given value (with RegEx)</li>
060: * <li>Property value does not contain a given value (with RegEx)</li>
061: * </ul>
062: *
063: * @author Michael Emmerich
064: *
065: * @version $Revision: 1.8 $
066: *
067: * @since 6.1.2
068: */
069: public class CmsContentCheckProperty extends A_CmsContentCheck {
070:
071: /** Path to the configuration file. */
072: private static final String CONFIGURATION = CmsContentCheck.VFS_PATH_PLUGIN_FOLDER
073: + "propertycheck/configuration.xml";
074:
075: /** Name of the dialog parameter. */
076: private static final String DIALOG_PARAMETER = "property";
077:
078: /** Path to the configuration icon. */
079: private static final String ICONPATH = "tools/contenttools/icons/big/contentcheck_property_configuration.png";
080:
081: /** The log object for this class. */
082: private static final Log LOG = CmsLog
083: .getLog(CmsContentCheckProperty.class);
084:
085: /** Name of this content check. */
086: private static final String NAME = "Property Check";
087:
088: /** The xpath for the empty configuration. */
089: private static final String XPATH_EMPTY = "empty";
090:
091: /** The xpath for the error configuration. */
092: private static final String XPATH_ERROR = "error";
093:
094: /** The xpath for the filename configuration. */
095: private static final String XPATH_FILENAME = "filename";
096:
097: /** The xpath for the length configuration. */
098: private static final String XPATH_LENGTH = "length";
099:
100: /** The xpath for the propertyname configuration. */
101: private static final String XPATH_PROPERTYNAME = "propertyname";
102:
103: /** The xpath for the type configuration. */
104: private static final String XPATH_TYPE = "type";
105:
106: /** The xpath for the value configuration. */
107: private static final String XPATH_VALUE = "value";
108:
109: /** The xpath for the warning configuration. */
110: private static final String XPATH_WARNUING = "warning";
111:
112: /** The active flag, signaling if this content check is active. */
113: private boolean m_active = true;
114:
115: /** The CmsObject. */
116: private CmsObject m_cms;
117:
118: /** List of all configured error checks. */
119: private List m_configuredErrorChecks = null;
120:
121: /** List of all configured warning checks. */
122: private List m_configuredWarningChecks = null;
123:
124: /** Locale to be used to extract xml content. */
125: private Locale m_locale;
126:
127: /**
128: *
129: * @see org.opencms.workplace.tools.content.check.I_CmsContentCheck#executeContentCheck(org.opencms.file.CmsObject, org.opencms.workplace.tools.content.check.CmsContentCheckResource)
130: */
131: public CmsContentCheckResource executeContentCheck(CmsObject cms,
132: CmsContentCheckResource testResource) throws CmsException {
133:
134: getConfiguration();
135: if (LOG.isDebugEnabled()) {
136: LOG.debug(Messages.get().getBundle().key(
137: Messages.LOG_DEBUG_PROPERTY_CONFIGURED_ERRORS_2,
138: new Object[] { testResource.getResourceName(),
139: m_configuredErrorChecks }));
140: }
141: // check for errors
142: List errors = processProperties(m_configuredErrorChecks,
143: testResource);
144: if (errors.size() > 0) {
145: testResource.addErrors(errors);
146: }
147: if (LOG.isDebugEnabled()) {
148: LOG.debug(Messages.get().getBundle().key(
149: Messages.LOG_DEBUG_PROPERTY_CONFIGURED_WARNINGS_2,
150: testResource.getResourceName(),
151: m_configuredErrorChecks));
152: }
153: // check for warnings
154: List warnings = processProperties(m_configuredWarningChecks,
155: testResource);
156: if (warnings.size() > 0) {
157: testResource.addWarnings(warnings);
158: }
159: return testResource;
160: }
161:
162: /**
163: *
164: * @see org.opencms.workplace.tools.content.check.I_CmsContentCheck#getDialogParameterName()
165: */
166: public String getDialogParameterName() {
167:
168: return DIALOG_PARAMETER;
169: }
170:
171: /**
172: * @see org.opencms.workplace.tools.I_CmsToolHandler#getHelpText()
173: */
174: public String getHelpText() {
175:
176: return Messages
177: .get()
178: .getBundle()
179: .key(
180: Messages.GUI_CHECKCONTENT_CONFIGURATION_PROPERTY_HELP_0);
181: }
182:
183: /**
184: * @see org.opencms.workplace.tools.I_CmsToolHandler#getIconPath()
185: */
186: public String getIconPath() {
187:
188: return ICONPATH;
189: }
190:
191: /**
192: * @see org.opencms.workplace.tools.I_CmsToolHandler#getLink()
193: */
194: public String getLink() {
195:
196: return "/system/workplace/views/admin/admin-editor.jsp?resource=/system/workplace/admin/contenttools/check/plugin/propertycheck/configuration.xml";
197: }
198:
199: /**
200: * @see org.opencms.workplace.tools.content.check.I_CmsContentCheck#getMessageBundles()
201: */
202: public List getMessageBundles() {
203:
204: List messages = new ArrayList();
205: messages.add(org.opencms.workplace.tools.content.check.Messages
206: .get().getBundleName());
207: return messages;
208: }
209:
210: /**
211: * @see org.opencms.workplace.tools.I_CmsToolHandler#getName()
212: */
213: public String getName() {
214:
215: return NAME;
216: }
217:
218: /**
219: * @see org.opencms.workplace.tools.I_CmsToolHandler#getPath()
220: */
221: public String getPath() {
222:
223: return "/contenttools/checkconfig/checkproperty";
224: }
225:
226: /**
227: * @see org.opencms.workplace.tools.I_CmsToolHandler#getPosition()
228: */
229: public float getPosition() {
230:
231: return 1;
232: }
233:
234: /**
235: * @see org.opencms.workplace.tools.I_CmsToolHandler#getShortName()
236: */
237: public String getShortName() {
238:
239: return NAME;
240: }
241:
242: /**
243: * @see org.opencms.workplace.tools.content.check.I_CmsContentCheck#init(org.opencms.file.CmsObject)
244: */
245: public void init(CmsObject cms) {
246:
247: m_cms = cms;
248: m_locale = new Locale("en");
249: }
250:
251: /**
252: * Gets the active flag.<p>
253: *
254: * @return true if this content check is active, false otherwise.
255: */
256: public boolean isActive() {
257:
258: return m_active;
259: }
260:
261: /**
262: * Sets the active flag.<p>
263: *
264: * This method is required to build the widget dialog frontend.
265: *
266: * @param value true if this content check is set to be active, false otherwise.
267: */
268: public void setActive(boolean value) {
269:
270: m_active = value;
271: }
272:
273: /**
274: * Gets the configuration of the property check.<p>
275: *
276: *@throws CmsException if an error occurs reading the configuration
277: */
278: private void getConfiguration() throws CmsException {
279:
280: if ((m_configuredErrorChecks == null)
281: || (m_configuredWarningChecks == null)) {
282: // get the configuration file
283: CmsResource res = m_cms.readResource(CONFIGURATION);
284: if (LOG.isDebugEnabled()) {
285: LOG.debug(Messages.get().getBundle().key(
286: Messages.LOG_DEBUG_PROPERTY_CONFIG_FILENAME_1,
287: res.getRootPath()));
288: }
289: CmsFile file = m_cms.readFile(res);
290: if (LOG.isDebugEnabled()) {
291: LOG.debug(Messages.get().getBundle().key(
292: Messages.LOG_DEBUG_PROPERTY_CONFIG_FILE_1,
293: new String(file.getContents())));
294: }
295: CmsXmlContent configuration = CmsXmlContentFactory
296: .unmarshal(m_cms, file);
297:
298: // now extract the configured error checks from it
299: m_configuredErrorChecks = getConfiguredChecks(
300: configuration, XPATH_ERROR);
301: m_configuredWarningChecks = getConfiguredChecks(
302: configuration, XPATH_WARNUING);
303: }
304: }
305:
306: /**
307: * Reads the configuration for a given xpath and stored all results in a list.<p>
308: *
309: * @param configuration the configuration to read from
310: * @param xpath the xpath prefix
311: * @return list of CmsContentCheckProperetyObject objects
312: */
313: private List getConfiguredChecks(CmsXmlContent configuration,
314: String xpath) {
315:
316: List checks = new ArrayList();
317:
318: if (LOG.isDebugEnabled()) {
319: LOG.debug(Messages.get().getBundle().key(
320: Messages.LOG_DEBUG_PROPERTY_CONFIG_XPATH_2, xpath,
321: m_locale));
322: }
323:
324: int size = configuration.getIndexCount(xpath, m_locale);
325: for (int i = 1; i <= size; i++) {
326: // extract the values from the configuration
327: String propertyname = configuration.getValue(
328: xpath + "[" + i + "]/" + XPATH_PROPERTYNAME,
329: m_locale).getStringValue(m_cms);
330: String type = configuration.getValue(
331: xpath + "[" + i + "]/" + XPATH_TYPE, m_locale)
332: .getStringValue(m_cms);
333: String empty = configuration.getValue(
334: xpath + "[" + i + "]/" + XPATH_EMPTY, m_locale)
335: .getStringValue(m_cms);
336: String filename = configuration.getValue(
337: xpath + "[" + i + "]/" + XPATH_FILENAME, m_locale)
338: .getStringValue(m_cms);
339: String length = configuration.getValue(
340: xpath + "[" + i + "]/" + XPATH_LENGTH, m_locale)
341: .getStringValue(m_cms);
342: int values = configuration.getIndexCount(xpath + "[" + i
343: + "]/" + XPATH_VALUE, m_locale);
344:
345: //String value = configuration.getValue(xpath + "[" + i + "]/" + XPATH_VALUE, m_locale).getStringValue(m_cms);
346:
347: // store them in the CmsContentCheckProperetyObject obejct for fürther processing
348: CmsContentCheckPropertyObject propObject = new CmsContentCheckPropertyObject();
349:
350: if (CmsStringUtil.isNotEmpty(propertyname)) {
351: propObject.setPropertyname(propertyname);
352: }
353: if (CmsStringUtil.isNotEmpty(type)) {
354: propObject.setType(type);
355: }
356: if (CmsStringUtil.isNotEmpty(empty)) {
357: propObject.setEmpty(empty.equals("true"));
358: }
359: if (CmsStringUtil.isNotEmpty(filename)) {
360: propObject.setFilename(filename.equals("true"));
361: }
362: if (CmsStringUtil.isNotEmpty(length)) {
363: propObject.setLength(new Integer(length).intValue());
364: }
365: if (values > 0) {
366: List valueList = new ArrayList();
367: for (int j = 1; j <= values; j++) {
368: String value = configuration.getValue(
369: xpath + "[" + i + "]/" + XPATH_VALUE + "["
370: + j + "]", m_locale)
371: .getStringValue(m_cms);
372: if (CmsStringUtil.isNotEmpty(value)) {
373: valueList.add(value);
374: }
375: }
376: propObject.setValue(valueList);
377: }
378:
379: if (LOG.isDebugEnabled()) {
380: LOG.debug(Messages.get().getBundle().key(
381: Messages.LOG_DEBUG_PROPERTY_CONFIG_PROPERTY_3,
382: new Integer(i), new Integer(size), propObject));
383: }
384:
385: checks.add(propObject);
386: }
387: return checks;
388: }
389:
390: /**
391: * Processes a list of CmsContentCheckProperetyObject and runs all available tests on them.<p>
392: *
393: * All errors or warnings found are collected in a list returned to the calling method.
394: *
395: * @param properties list of CmsContentCheckProperetyObject to process
396: * @param testResource the CmsContentCheckResource to run all tests on
397: * @return list of Strings containing either errors or warinings
398: */
399: private List processProperties(List properties,
400: CmsContentCheckResource testResource) {
401:
402: List results = new ArrayList();
403:
404: if (LOG.isDebugEnabled()) {
405: LOG.debug(Messages.get().getBundle().key(
406: Messages.LOG_DEBUG_PROPERTY_RESOURCE_1,
407: testResource.getResourceName()));
408: }
409:
410: //loop through all property tests
411: for (int i = 0; i < properties.size(); i++) {
412: try {
413: CmsContentCheckPropertyObject propObject = (CmsContentCheckPropertyObject) properties
414: .get(i);
415:
416: if (LOG.isDebugEnabled()) {
417: LOG.debug(Messages.get().getBundle().key(
418: Messages.LOG_DEBUG_PROPERTY_PROPERTY_1,
419: propObject.toString()));
420: }
421:
422: // check if this test must be done for thies kind of resource
423: if ((propObject.getType()
424: .equals(CmsContentCheckPropertyObject.TYPE_BOTH))
425: || ((propObject
426: .getType()
427: .equals(
428: CmsContentCheckPropertyObject.TYPE_FILE) && (testResource
429: .getResource().isFile())))
430: || ((propObject
431: .getType()
432: .equals(
433: CmsContentCheckPropertyObject.TYPE_FOLDER) && (testResource
434: .getResource().isFolder())))
435:
436: ) {
437:
438: // read the property
439: String prop = m_cms.readPropertyObject(
440: testResource.getResource(),
441: propObject.getPropertyname(), false)
442: .getValue();
443:
444: if (LOG.isDebugEnabled()) {
445: LOG.debug(Messages.get().getBundle().key(
446: Messages.LOG_DEBUG_PROPERTY_VALUE_1,
447: prop));
448: }
449:
450: if (LOG.isDebugEnabled()) {
451: LOG
452: .debug(Messages
453: .get()
454: .getBundle()
455: .key(
456: Messages.LOG_DEBUG_PROPERTY_ISEMPTYCHECK_1,
457: Boolean
458: .valueOf(propObject
459: .isEmpty())));
460: }
461:
462: // test if the property is empty
463: if (propObject.isEmpty()
464: && CmsStringUtil.isEmpty(prop)) {
465: results.add(Messages.get().getBundle().key(
466: Messages.ERR_CHECK_NO_PROPERTYNAME_1,
467: propObject.getPropertyname()));
468: if (LOG.isDebugEnabled()) {
469: LOG
470: .debug(Messages
471: .get()
472: .getBundle()
473: .key(
474: Messages.ERR_CHECK_NO_PROPERTYNAME_1,
475: propObject
476: .getPropertyname()));
477: }
478: }
479:
480: if (LOG.isDebugEnabled()) {
481: LOG
482: .debug(Messages
483: .get()
484: .getBundle()
485: .key(
486: Messages.LOG_DEBUG_PROPERTY_ISFILENAME_1,
487: Boolean
488: .valueOf(propObject
489: .isFilename())));
490: }
491:
492: // test if the property does not start with the filename
493: if (!CmsStringUtil.isEmpty(prop)) {
494: if (propObject.isFilename()
495: && testResource.getResource().getName()
496: .toLowerCase().startsWith(
497: prop.toLowerCase())) {
498: results
499: .add(Messages
500: .get()
501: .getBundle()
502: .key(
503: Messages.ERR_CHECK_CONTAINS_FILENAME_2,
504: propObject
505: .getPropertyname(),
506: prop));
507: if (LOG.isDebugEnabled()) {
508: LOG
509: .debug(Messages
510: .get()
511: .getBundle()
512: .key(
513: Messages.ERR_CHECK_CONTAINS_FILENAME_2,
514: propObject
515: .getPropertyname(),
516: prop));
517: }
518: }
519:
520: if (LOG.isDebugEnabled()) {
521: LOG
522: .debug(Messages
523: .get()
524: .getBundle()
525: .key(
526: Messages.LOG_DEBUG_PROPERTY_CHECKLENGTH_2,
527: new Integer(
528: propObject
529: .getLength()),
530: new Integer(prop
531: .length())));
532: }
533: // test if the minmal property length is valid
534: if (propObject.getLength() > -1) {
535: if (prop.length() < propObject.getLength()) {
536: results
537: .add(Messages
538: .get()
539: .getBundle()
540: .key(
541: Messages.ERR_CHECK_TOO_SHORT_3,
542: propObject
543: .getPropertyname(),
544: prop,
545: new Integer(
546: prop
547: .length())));
548: if (LOG.isDebugEnabled()) {
549: LOG
550: .debug(Messages
551: .get()
552: .getBundle()
553: .key(
554: Messages.ERR_CHECK_TOO_SHORT_3,
555: propObject
556: .getPropertyname(),
557: prop,
558: new Integer(
559: prop
560: .length())));
561: }
562: }
563: }
564:
565: // test if the value matches a regex
566: if (propObject.getValue().size() > 0) {
567: for (int j = 0; j < propObject.getValue()
568: .size(); j++) {
569:
570: String regex = (String) propObject
571: .getValue().get(j);
572:
573: boolean matchResult = true;
574: if (regex.charAt(0) == '!') {
575: // negate the pattern
576: matchResult = false;
577: regex = regex.substring(1);
578: }
579: String matchValue = prop;
580: boolean match = Pattern.matches(regex,
581: matchValue);
582:
583: if (LOG.isDebugEnabled()) {
584: LOG
585: .debug(Messages
586: .get()
587: .getBundle()
588: .key(
589: Messages.LOG_DEBUG_PROPERTY_MATCHPATTERN_2,
590: regex,
591: matchValue));
592: }
593:
594: if (matchResult != match) {
595: results
596: .add(Messages
597: .get()
598: .getBundle()
599: .key(
600: Messages.ERR_CHECK_MATCH_3,
601: propObject
602: .getPropertyname(),
603: prop,
604: propObject
605: .getValue()
606: .get(
607: j)));
608: if (LOG.isDebugEnabled()) {
609: LOG
610: .debug(Messages
611: .get()
612: .getBundle()
613: .key(
614: Messages.ERR_CHECK_MATCH_3,
615: propObject
616: .getPropertyname(),
617: prop,
618: propObject
619: .getValue()
620: .get(
621: j)));
622: }
623: }
624: }
625: }
626: }
627: }
628:
629: } catch (CmsException e) {
630: LOG.error(Messages.get().getBundle().key(
631: Messages.LOG_ERROR_PROCESSING_PROPERTIES_2,
632: testResource.getResourceName(), e));
633: }
634: }
635:
636: return results;
637: }
638: }
|