View Javadoc

1   /*
2    * Copyright 2004-2006 the Seasar Foundation and the Others.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 
13   * either express or implied. See the License for the specific language
14   * governing permissions and limitations under the License.
15   */
16  package org.seasar.tuigwaa.plugin.database;
17  
18  import java.io.BufferedReader;
19  import java.io.IOException;
20  import java.io.InputStream;
21  import java.io.InputStreamReader;
22  import java.io.UnsupportedEncodingException;
23  import java.net.URL;
24  
25  import javax.servlet.http.HttpServletRequest;
26  import javax.servlet.http.HttpServletResponse;
27  
28  import org.apache.commons.logging.Log;
29  import org.apache.commons.logging.LogFactory;
30  import org.apache.struts.util.ResponseUtils;
31  import org.seasar.tuigwaa.cms.core.CmsRequest;
32  import org.seasar.tuigwaa.cms.core.CmsResponse;
33  import org.seasar.tuigwaa.cms.core.wiki.WikiContext;
34  import org.seasar.tuigwaa.database.DataTable;
35  import org.seasar.tuigwaa.database.function.criteria.CriteriaListFunction;
36  import org.seasar.tuigwaa.database.function.criteria.EqCriteriaFunction;
37  import org.seasar.tuigwaa.database.function.criteria.OrderCriteriaFunction;
38  import org.seasar.tuigwaa.model.DAOService;
39  import org.seasar.tuigwaa.model.common.EntityDAO;
40  import org.seasar.tuigwaa.model.core.TgwEntity;
41  import org.seasar.tuigwaa.plugin.AbstractTgwPlugin;
42  import org.seasar.tuigwaa.plugin.PluginException;
43  import org.seasar.tuigwaa.plugin.PluginRequest;
44  import org.seasar.tuigwaa.plugin.TgwPluginUtils;
45  import org.seasar.tuigwaa.system.Constants;
46  import org.seasar.tuigwaa.util.TgwContext;
47  
48  import com.isenshi.util.CharUtil;
49  import com.isenshi.util.HtmlBuffer;
50  import com.isenshi.util.XMLStringBuffer;
51  import com.isenshi.util.extlib.StrutsUtil;
52  
53  /***
54   * Tracback Plugin
55   * 
56   * @author someda
57   * @see <a href="http://www.sixapart.com/pronet/docs/trackback_spec">TrackBack
58   *      Technical Specification</a>
59   */
60  public class TrackbackPlugin extends AbstractTgwPlugin {
61  
62  	private Log log = LogFactory.getLog(getClass());
63  
64  	private static final String CHARSET_FILTER_ENCODING = "Windows-31J";
65  
66  	private static final String CHARSET_SYSTEM_ENCODING = "UTF-8";
67  
68  	private static final String PARAM_PAGENAME = getParameterName("trackback.name");
69  
70  	private static final int ERRORNO_SUCCESS = 0;
71  
72  	private static final int ERRORNO_FAILED = 1;
73  
74  	private static final int DEFAULT_DISPLAY_NUMBER = 10;
75  
76  	// Trackback Ping HTTP Parameter names.
77  	private static final String TRACKBACKPING_PARAM_URL = "url"; // required
78  
79  	private static final String TRACKBACKPING_PARAM_TITLE = "title"; // optional
80  
81  	private static final String TRACKBACKPING_PARAM_EXCERPT = "excerpt"; // optional
82  
83  	private static final String TRACKBACKPING_PARAM_BLOGNAME = "blog_name"; // optional
84  
85  	// private static final String TRACKBACKPING_CONTENTTYPE =
86  	// "application/x-www-form-urlencoded; charset=utf-8";
87  
88  	private static final String ENTITY_TRACKBACK_PAGENAME = "pagename";
89  
90  	protected void initialize(CmsRequest request, CmsResponse response,
91  			PluginRequest prequest) throws PluginException {
92  		String siteName = request.getSiteName();
93  		requireEntity(siteName, Trackback.class);
94  	}
95  
96  	public String doHTMLView(CmsRequest request, CmsResponse response,
97  			PluginRequest prequest) throws PluginException {
98  
99  		String pagename = request.getPage().getResource().getPath();
100 		request.setParameter(PARAM_PAGENAME, pagename);
101 
102 		int number = DEFAULT_DISPLAY_NUMBER;
103 		String[] args = prequest.getArgs();
104 		if (args != null) {
105 			try {
106 				number = Integer.parseInt(args[0]);
107 			} catch (NumberFormatException nfe) {
108 				log.error("argment invalid and ignore it");
109 				number = DEFAULT_DISPLAY_NUMBER;
110 			}
111 		}
112 
113 		WikiContext ctx = getConfiguration().getWikiContext();
114 		String url = ctx.getPluginProxyURL(prequest.getName(), request)
115 				.toString();
116 		HtmlBuffer buf = new HtmlBuffer();
117 		buf.appendBody(getMessage("trackback.trackback.url"));
118 		buf.appendStartTag(HtmlBuffer.TAG_INPUT);
119 		buf.appendAttribute("size", "120");
120 		buf.appendAttribute("value", url);
121 		buf.endTag();
122 
123 		// get TrackBacks previously got
124 		TrackbackDAO dao = getTrackbackDAO();
125 		DataTable dataTable = dao.getTrackbacks(request.getSiteName(),
126 				pagename, null);
127 
128 		if (dataTable != null) {
129 			boolean tagStart = false;
130 			while (dataTable.hasNext() && number > 0) {
131 
132 				if (!tagStart) {
133 					buf.appendStartTag("ul");
134 					tagStart = true;
135 				}
136 
137 				dataTable.next();
138 				Trackback trackback = (Trackback) dataTable.getRowObject();
139 
140 				String title = trackback.getTitle();
141 				String trackbackurl = trackback.getUrl();
142 				String date = trackback.getModificationDate().toString();
143 
144 				buf.appendStartTag("li");
145 				buf.appendBody("[" + date + "]");
146 				//				
147 				if (title != null && !title.equals("")) {
148 					// buf.appendAnchor(trackbackurl,title);
149 					// }else{
150 					buf.appendAnchor(trackbackurl, trackbackurl);
151 					// }
152 				}
153 				buf.endTag();
154 				number--;
155 			}
156 			if (tagStart)
157 				buf.endTag();
158 		}
159 		return buf.toString();
160 	}
161 
162 	public String doAction(HttpServletRequest request,
163 			HttpServletResponse response) {
164 
165 		String returnXML = null;
166 
167 		String method = request.getMethod();
168 		String pagename = StrutsUtil.getURLDecodedParameter(request,
169 				PARAM_PAGENAME);
170 
171 		if (!"post".equalsIgnoreCase(method)) {
172 			return CharUtil.urlDecode(pagename);
173 		}
174 
175 		String url = request.getParameter(TRACKBACKPING_PARAM_URL);
176 		// <> → &lt;,&gt;
177 		if (url == null) {
178 			String msg = TRACKBACKPING_PARAM_URL + " must be given.";
179 			log.error(msg);
180 			returnXML = generateReturnXML(ERRORNO_FAILED, msg);
181 		} else {
182 			if (!isContainsUrl(url, pagename, request)) {// validate URL and
183 				// contents
184 				String msg = "source URL is invalid or doesn't contain this URL as contents.";
185 				log.error(msg);
186 				returnXML = generateReturnXML(ERRORNO_FAILED, msg);
187 			} else {
188 				String siteName = TgwContext.getSiteName();
189 				// all ok about URL and contents, proceeding...
190 
191 				log
192 						.info("trackback Content-Type : "
193 								+ request.getContentType());
194 
195 				String title = request.getParameter(TRACKBACKPING_PARAM_TITLE);
196 				String blogname = request
197 						.getParameter(TRACKBACKPING_PARAM_BLOGNAME);
198 				String excerpt = request
199 						.getParameter(TRACKBACKPING_PARAM_EXCERPT);
200 
201 				try {
202 					title = new String(title.getBytes(CHARSET_FILTER_ENCODING),
203 							CHARSET_SYSTEM_ENCODING);
204 					blogname = new String(blogname
205 							.getBytes(CHARSET_FILTER_ENCODING),
206 							CHARSET_SYSTEM_ENCODING);
207 					excerpt = new String(excerpt
208 							.getBytes(CHARSET_FILTER_ENCODING),
209 							CHARSET_SYSTEM_ENCODING);
210 
211 					log.info("=------------------- after ------------------");
212 					log.info("title :" + title + " blogname :" + blogname);
213 					log.info("excerpt " + excerpt);
214 				} catch (UnsupportedEncodingException uee) {
215 					uee.printStackTrace();
216 				}
217 
218 				// store TRACKBACK data
219 				try {
220 					Trackback bean = getTrackbackBean(siteName, pagename, url,
221 							title, blogname, excerpt);
222 					getTrackbackDAO().save(bean);
223 					returnXML = generateReturnXML(ERRORNO_SUCCESS, null);
224 				} catch (Exception e) {
225 					String msg = "sorry, storing trackback ping data failed.";
226 					log.error(msg);
227 					returnXML = generateReturnXML(ERRORNO_FAILED, msg);
228 				}
229 			}
230 		}
231 		response.setContentType("text/xml;charset=UTF-8");
232 		try {
233 			response.getWriter().write(returnXML);
234 		} catch (IOException ioe) {
235 			ioe.printStackTrace();
236 		}
237 		return null;
238 	}
239 
240 	private String generateReturnXML(int errorno, String message) {
241 
242 		XMLStringBuffer buf = new XMLStringBuffer();
243 		buf.appendXMLDeclaration("UTF-8", null);
244 		buf.setTab(false);
245 		buf.appendStartTag("response");
246 
247 		buf.appendStartTag("error");
248 		buf.setNewline(false);
249 		buf.appendBody(String.valueOf(errorno));
250 		if (message != null && !message.equals("")) {
251 			buf.setNewline(true);
252 			buf.endTag();
253 			buf.appendStartTag("message");
254 			buf.setNewline(false);
255 			buf.appendBody(message);
256 		}
257 		buf.setNewline(true);
258 		buf.endAllTags();
259 		return buf.toString();
260 	}
261 
262 	private boolean isContainsUrl(String url, String pagename,
263 			HttpServletRequest request) {
264 
265 		boolean containsUrl = false;
266 		String serverName = request.getServerName();
267 		log.info("trackback request comes from " + url + " to " + serverName);
268 		try {
269 			URL srcUrl = new URL(url);
270 			InputStream is = srcUrl.openStream();
271 			BufferedReader br = new BufferedReader(new InputStreamReader(is));
272 			while (true) {
273 				String line = br.readLine();
274 				if (line == null)
275 					break;
276 				if (line.indexOf(serverName) != -1) {
277 					containsUrl = true;
278 					break;
279 				}
280 			}
281 			br.close();
282 			is.close();
283 		} catch (IOException ioe) {
284 			log.error("error occured during reading URL : " + url);
285 		}
286 		containsUrl = true; // temporaly
287 		return containsUrl;
288 	}
289 
290 	private Trackback getTrackbackBean(String siteName, String pagename,
291 			String url, String title, String blogName, String excerpt)
292 			throws PluginException {
293 
294 		Trackback trackback = new Trackback();
295 
296 		// already exists or not for given pagename and source URL
297 		DataTable dataTable = getTrackbackDAO().getTrackbacks(siteName,
298 				pagename, url);
299 		if (dataTable.hasNext()) {
300 			dataTable.next();
301 			Trackback aTrackback = (Trackback) dataTable.getRowObject();
302 			trackback.setId(aTrackback.getId());
303 		}
304 
305 		trackback.setPagename(pagename);
306 		trackback.setUrl(url.replaceAll("<", "&lt;").replaceAll(">", "&gt;"));
307 
308 		if (title != null && !title.equals(""))
309 			trackback.setTitle(ResponseUtils.filter(title));
310 		if (blogName != null && !blogName.equals(""))
311 			trackback.setBlogName(ResponseUtils.filter(blogName));
312 		if (excerpt != null && !excerpt.equals(""))
313 			trackback.setExcerpt(ResponseUtils.filter(excerpt));
314 
315 		return trackback;
316 	}
317 
318 	private TrackbackDAO getTrackbackDAO() throws PluginException {
319 		String siteName = TgwContext.getSiteName();
320 
321 		String entityName = TgwPluginUtils.toPluginEntityName(Trackback.class);
322 		TgwEntity entity = getEntity(siteName, entityName);
323 		if (entity == null) {
324 			entity = requireEntity(siteName, Trackback.class);
325 		}
326 		// TgwEntity entity = requireEntity(siteName, Trackback.class);
327 		return new TrackbackDAO(entity);
328 	}
329 
330 	class TrackbackDAO {
331 
332 		DAOService daoService = (DAOService) getService(DAOService.class);
333 
334 		EntityDAO dao;
335 
336 		TrackbackDAO(TgwEntity trackback) {
337 			dao = daoService.getDAO(trackback);
338 		}
339 
340 		void save(Trackback trackback) {
341 			dao.saveOrUpdate(trackback);
342 		}
343 
344 		DataTable getTrackbacks(String siteName, String pageName, String url) {
345 			CriteriaListFunction function = new CriteriaListFunction();
346 			EqCriteriaFunction eq = new EqCriteriaFunction(
347 					ENTITY_TRACKBACK_PAGENAME, pageName);
348 			OrderCriteriaFunction order = new OrderCriteriaFunction(
349 					Constants.ENTITY_BUILTIN_MODIFICATIONDATE, null, true);
350 			function.addFunction(eq);
351 			function.addFunction(order);
352 			if (url != null) {
353 				EqCriteriaFunction urleq = new EqCriteriaFunction(
354 						TRACKBACKPING_PARAM_URL, url);
355 				function.addFunction(urleq);
356 			}
357 			return getDataTable(siteName, Trackback.class, function);
358 		}
359 	}
360 }