/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to you 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
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
* Copyright 2013 Josh Elser
*
*/
package cosmos.mapred;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import org.apache.accumulo.core.data.Mutation;
import org.apache.accumulo.core.data.Value;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
import org.mediawiki.xml.export_0.ContributorType;
import org.mediawiki.xml.export_0.MediaWikiType;
import org.mediawiki.xml.export_0.PageType;
import org.mediawiki.xml.export_0.RevisionType;
import com.sun.xml.bind.api.ClassResolver;
import cosmos.mediawiki.MediawikiPage.Page;
import cosmos.mediawiki.MediawikiPage.Page.Revision;
import cosmos.mediawiki.MediawikiPage.Page.Revision.Contributor;
/**
*
*/
public class MediawikiMapper extends Mapper<LongWritable,Text,Text,Mutation> {
private static final Text tableName = new Text("sortswiki");
private static final Text empty = new Text("");
private static Object lock = new Object();
private static JAXBContext jaxbCtx;
private Unmarshaller unmarshaller;
public MediawikiMapper() {
synchronized(lock) {
try {
jaxbCtx = JAXBContext.newInstance("org.mediawiki.xml.export_0", ClassLoader.getSystemClassLoader());
} catch (JAXBException e) {
throw new RuntimeException(e);
}
}
}
/**
* Called once at the beginning of the task.
*/
@Override
protected void setup(Context context) throws IOException, InterruptedException {
try {
this.unmarshaller = jaxbCtx.createUnmarshaller();
this.unmarshaller.setProperty(ClassResolver.class.getName(), new ClassResolver() {
@Override
public Class<?> resolveElementName(String nsUri, String localName) throws Exception {
if ("page".equalsIgnoreCase(localName)) {
return PageType.class;
} else {
return MediaWikiType.class;
}
}
});
} catch (JAXBException e) {
throw new RuntimeException(e);
}
}
/**
* Called once for each key/value pair in the input split. Most applications should override this, but the default is the identity function.
*/
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
Object o;
try {
o = unmarshaller.unmarshal(new ByteArrayInputStream(value.getBytes(), 0, value.getLength()));
} catch (JAXBException e) {
throw new IOException("Couldn't unmarshall '" + value + "'", e);
}
PageType pageType = (PageType) o;
Page page = pageTypeToPage(pageType);
Value protobufValue = new Value(page.toByteArray());
Mutation m = new Mutation(Long.toString(page.getId()));
m.put(empty, empty, protobufValue);
context.write(tableName, m);
}
protected Page pageTypeToPage(PageType pageType) {
Page.Builder builder = Page.newBuilder();
builder.setId(pageType.getId().longValue());
List<Object> children = pageType.getRevisionOrUploadOrLogitem();
if (null != children) {
for (Object o : children) {
if (o instanceof RevisionType) {
RevisionType revision = (RevisionType) o;
Revision.Builder revBuilder = Revision.newBuilder();
revBuilder.setId(revision.getId().longValue());
revBuilder.setTimestamp(revision.getTimestamp().toString());
ContributorType contributor = revision.getContributor();
if (contributor != null) {
Contributor.Builder conBuilder = Contributor.newBuilder();
if (null != contributor.getId()) {
conBuilder.setId(contributor.getId().longValue());
}
if (null != contributor.getUsername()) {
conBuilder.setUsername(contributor.getUsername());
}
revBuilder.setContributor(conBuilder.build());
}
builder.setRevision(revBuilder.build());
break;
}
}
}
return builder.build();
}
/**
* Called once at the end of the task.
*/
@Override
protected void cleanup(Context context) throws IOException, InterruptedException {
}
}