001/* 002 * Copyright 2010 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.ametys.cms.transformation; 018 019import java.net.CookieHandler; 020import java.net.CookieManager; 021import java.net.CookiePolicy; 022import java.util.Collection; 023import java.util.Collections; 024 025import org.apache.avalon.framework.component.Component; 026import org.apache.avalon.framework.logger.AbstractLogEnabled; 027import org.apache.avalon.framework.service.ServiceException; 028import org.apache.avalon.framework.service.ServiceManager; 029import org.apache.avalon.framework.service.Serviceable; 030 031import org.ametys.core.util.HttpUrlUtils; 032import org.ametys.core.util.HttpUrlUtils.HttpCheck; 033import org.ametys.core.version.Version; 034import org.ametys.core.version.VersionsHandler; 035import org.ametys.runtime.i18n.I18nizableText; 036 037/** 038 * Consistency checker component. 039 * Checks the state of the links extracted as outgoing references for a content. 040 */ 041public class ConsistencyChecker extends AbstractLogEnabled implements Serviceable, Component 042{ 043 /** Avalon role */ 044 public static final String ROLE = ConsistencyChecker.class.getName(); 045 046 /** Constants for the special external type for outgoing references */ 047 public static final String CONSISTENCY_EXTERNAL_REFERENCE_TYPE = "__external"; 048 049 /** The state of the check */ 050 public enum CHECK 051 { 052 /** If the check was all right */ 053 SUCCESS, 054 /** Server Error. */ 055 SERVER_ERROR, 056 /** Not Found.*/ 057 NOT_FOUND, 058 /** Unauthorized. */ 059 UNAUTHORIZED, 060 /** If the check may be too long */ 061 UNKNOWN; 062 063 /** 064 * Convert a {@link HttpCheck} value to a {@link CHECK} value 065 * @param httpCheck the HTTP check 066 * @return the CHECK value 067 */ 068 public static CHECK from(HttpCheck httpCheck) 069 { 070 switch (httpCheck) 071 { 072 case SUCCESS: 073 return CHECK.SUCCESS; 074 075 case TIMEOUT: 076 case SECURITY_LEVEL_ERROR: 077 case REDIRECT: 078 return CHECK.UNKNOWN; 079 080 case NOT_FOUND: 081 return CHECK.NOT_FOUND; 082 083 case SERVER_ERROR: 084 default: 085 return CHECK.SERVER_ERROR; 086 } 087 } 088 } 089 090 /** The ametys uri resolver */ 091 protected URIResolverExtensionPoint _uriResolverEP; 092 /** The version handler */ 093 protected VersionsHandler _versionsHandler; 094 /** The URL utils */ 095 protected HttpUrlUtils _urlUtils; 096 097 @Override 098 public void service(ServiceManager manager) throws ServiceException 099 { 100 _uriResolverEP = (URIResolverExtensionPoint) manager.lookup(URIResolverExtensionPoint.ROLE); 101 _versionsHandler = (VersionsHandler) manager.lookup(VersionsHandler.ROLE); 102 _urlUtils = (HttpUrlUtils) manager.lookup(HttpUrlUtils.ROLE); 103 } 104 105 /** 106 * Check the consistency of a reference 107 * @param referenceType The type of the reference to test (can be 'attachment', 'explorer', 'metadata', '__external', etc...) 108 * @param referenceValue The value of the reference to test 109 * @param shortTest true to make a short test, that means that long tests will return UNKNOWN immediately. If false, you will always have a SUCCESS or a FAILURE. 110 * @return CHECK enum value 111 */ 112 public CHECK checkConsistency(String referenceType, String referenceValue, boolean shortTest) 113 { 114 if (getLogger().isDebugEnabled()) 115 { 116 getLogger().debug("Checking consistency for URI of type '" + referenceType + "' with uri '" + referenceValue + "'"); 117 } 118 119 URIResolver resolver = _uriResolverEP.getResolverForType(referenceType); 120 if (resolver == null) 121 { 122 // No resolver for external references 123 if (CONSISTENCY_EXTERNAL_REFERENCE_TYPE.equals(referenceType)) 124 { 125 if (referenceValue.startsWith("http:") || referenceValue.startsWith("https:")) 126 { 127 return _checkHTTPLink(referenceValue, shortTest); 128 } 129 else if (referenceValue.startsWith("mailto:")) 130 { 131 return CHECK.SUCCESS; 132 } 133 else if (referenceValue.startsWith("tel:")) 134 { 135 return CHECK.SUCCESS; 136 } 137 } 138 139 if (getLogger().isDebugEnabled()) 140 { 141 getLogger().debug("Cannot test external link '" + referenceValue + "'"); 142 } 143 144 return CHECK.UNKNOWN; 145 } 146 else 147 { 148 return resolver.checkLink(referenceValue, shortTest); 149 } 150 } 151 152 /** 153 * Get the label of a reference. 154 * @param referenceType The type of the reference to test (can be 'attachment', 'explorer', 'metadata', '__external', etc...) 155 * @param referenceValue The value of the reference to test 156 * @return the element label. 157 */ 158 public I18nizableText getLabel(String referenceType, String referenceValue) 159 { 160 URIResolver resolver = _uriResolverEP.getResolverForType(referenceType); 161 if (resolver == null) 162 { 163 return new I18nizableText("plugin.cms", "PLUGINS_CMS_LINK_EXTERNAL_LABEL", Collections.singletonList(referenceValue)); 164 } 165 else 166 { 167 return resolver.getLabel(referenceValue); 168 } 169 } 170 171 /** 172 * Test an http link 173 * @param linkValue The http url to test 174 * @param shortTest true to make a short test (with short timeout) 175 * @return The state. UNKNOWN if test cannot be done fully 176 */ 177 protected CHECK _checkHTTPLink(String linkValue, boolean shortTest) 178 { 179 try 180 { 181 CookieHandler.setDefault(new CookieManager(null, CookiePolicy.ACCEPT_ALL)); 182 183 String httpUrl = linkValue.replaceAll(" ", "%20"); 184 String userAgent = "Ametys/" + _getCMSVersion(); 185 int timeout = shortTest ? 1000 : -1; 186 int readTimeout = shortTest ? 2000 : -1; 187 HttpCheck checkURL = HttpUrlUtils.checkHttpUrl(httpUrl, userAgent, null, timeout, readTimeout, true); 188 189 return CHECK.from(checkURL); 190 } 191 finally 192 { 193 ((CookieManager) CookieHandler.getDefault()).getCookieStore().removeAll(); 194 } 195 } 196 197 private String _getCMSVersion() 198 { 199 Collection<Version> versions = _versionsHandler.getVersions(); 200 for (Version version : versions) 201 { 202 if (version.getName().equals("CMS")) 203 { 204 return version.getVersion(); 205 } 206 } 207 return null; 208 } 209}