/*******************************************************************************
* Copyright (c) 2006-2010 eBay Inc. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*******************************************************************************/
/*******************************************************************************
* Copyright (c) 2007, 2009 David Green and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* David Green - initial API and implementation
*******************************************************************************/
package org.ebayopensource.mylyn.wikitext.confluence.core.tasks;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.taskdefs.Get;
import org.eclipse.mylyn.wikitext.core.util.IgnoreDtdEntityResolver;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
class ConfluenceApiImageFetchingStrategy extends ImageFetchingStrategy {
private final Pattern imageTitlePattern = Pattern.compile("(?\\|title=(.+)"); //$NON-NLS-1$
private URL url;
private String pageName;
@Override
public void fetchImages() {
if (pageName == null || pageName.length() == 0) {
throw new BuildException("please specify @pageName"); //$NON-NLS-1$
}
if (!pageName.equals(pageName.trim())) {
throw new BuildException("@pageName must not have leading or training whitespace"); //$NON-NLS-1$
}
String base;
try {
base = url.toURI().toString();
} catch (URISyntaxException e) {
throw new BuildException(e);
}
if (!base.endsWith("/")) { //$NON-NLS-1$
base += "/"; //$NON-NLS-1$
}
URL apiUrl;
try {
String queryString = String.format(
"action=query&titles=%s&generator=images&prop=imageinfo&iiprop=url&format=xml", URLEncoder.encode(pageName, "UTF-8")); //$NON-NLS-1$ //$NON-NLS-2$
apiUrl = new URL(base + "api.php?" + queryString); //$NON-NLS-1$
} catch (Exception e) {
throw new BuildException("Cannot compose API URL", e); //$NON-NLS-1$
}
Reader input;
try {
input = new InputStreamReader(new BufferedInputStream(apiUrl.openStream()), "UTF-8"); //$NON-NLS-1$
} catch (IOException e) {
throw new BuildException(String.format("Cannot contact %s: %s", apiUrl, e.getMessage()), e); //$NON-NLS-1$
}
final SAXParserFactory parserFactory = SAXParserFactory.newInstance();
parserFactory.setNamespaceAware(true);
parserFactory.setValidating(false);
try {
SAXParser saxParser = parserFactory.newSAXParser();
XMLReader xmlReader = saxParser.getXMLReader();
xmlReader.setEntityResolver(IgnoreDtdEntityResolver.getInstance());
ImageFetchingContentHandler contentHandler = new ImageFetchingContentHandler();
xmlReader.setContentHandler(contentHandler);
try {
xmlReader.parse(new InputSource(input));
} catch (IOException e) {
throw new BuildException(String.format("Unexpected exception retrieving data from %s", apiUrl), e); //$NON-NLS-1$
} finally {
try {
input.close();
} catch (IOException e) {
// ignore
}
}
int fileCount = 0;
for (Map.Entry<String, String> ent : contentHandler.imageTitleToUrl.entrySet()) {
String title = ent.getKey();
String imageUrl = ent.getValue();
Matcher titleMatcher = imageTitlePattern.matcher(title);
if (titleMatcher.matches()) {
String name = titleMatcher.group(1);
name = name.replace(' ', '_');
String qualifiedUrl = base;
if (imageUrl.matches("https?://.*")) { //$NON-NLS-1$
qualifiedUrl = imageUrl;
} else {
if (imageUrl.startsWith("/")) { //$NON-NLS-1$
qualifiedUrl += imageUrl.substring(0);
} else {
qualifiedUrl += imageUrl;
}
}
log("Fetching " + qualifiedUrl, Project.MSG_INFO); //$NON-NLS-1$
Get get = new Get();
get.setProject(getProject());
get.setLocation(getLocation());
try {
get.setSrc(new URL(qualifiedUrl));
} catch (MalformedURLException e) {
log("Skipping " + url + ": " + e.getMessage(), Project.MSG_WARN); //$NON-NLS-1$ //$NON-NLS-2$
continue;
}
get.setDest(new File(dest, name));
get.execute();
++fileCount;
} else {
log(String.format("Unexpected title format: %s", title), Project.MSG_WARN); //$NON-NLS-1$
}
}
log("Fetched " + fileCount + " image files for " + pageName, Project.MSG_INFO); //$NON-NLS-1$ //$NON-NLS-2$
} catch (SAXException e) {
throw new BuildException("Unexpected error in XML content", e); //$NON-NLS-1$
} catch (ParserConfigurationException e) {
throw new BuildException("Cannot configure SAX parser", e); //$NON-NLS-1$
}
}
public URL getUrl() {
return url;
}
public void setUrl(URL url) {
this.url = url;
}
public String getPageName() {
return pageName;
}
public void setPageName(String pageName) {
this.pageName = pageName;
}
private class ImageFetchingContentHandler implements ContentHandler {
final Map<String, String> imageTitleToUrl = new HashMap<String, String>();
private String currentPage = null;
private boolean inImageInfo = false;
public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
if ("page".equals(localName)) { //$NON-NLS-1$
currentPage = atts.getValue("title"); //$NON-NLS-1$
} else if ("imageinfo".equals(localName)) { //$NON-NLS-1$
inImageInfo = true;
} else if (inImageInfo && "ii".equals(localName)) { //$NON-NLS-1$
imageTitleToUrl.put(currentPage, atts.getValue("url")); //$NON-NLS-1$
}
}
public void endElement(String uri, String localName, String qName) throws SAXException {
if ("page".equals(localName)) { //$NON-NLS-1$
currentPage = null;
} else if ("imageinfo".equals(localName)) { //$NON-NLS-1$
inImageInfo = false;
}
}
public void characters(char[] ch, int start, int length) throws SAXException {
}
public void endDocument() throws SAXException {
}
public void endPrefixMapping(String prefix) throws SAXException {
}
public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
}
public void processingInstruction(String target, String data) throws SAXException {
}
public void setDocumentLocator(Locator locator) {
}
public void skippedEntity(String name) throws SAXException {
}
public void startDocument() throws SAXException {
}
public void startPrefixMapping(String prefix, String uri) throws SAXException {
}
}
}