/*
* Copyright © 2014 Cask Data, Inc.
*
* 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
*
* 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.
*/
package co.cask.cdap.test.app;
import co.cask.cdap.api.annotation.ProcessInput;
import co.cask.cdap.api.annotation.Tick;
import co.cask.cdap.api.annotation.UseDataSet;
import co.cask.cdap.api.app.AbstractApplication;
import co.cask.cdap.api.common.Bytes;
import co.cask.cdap.api.dataset.lib.KeyValueTable;
import co.cask.cdap.api.flow.AbstractFlow;
import co.cask.cdap.api.flow.flowlet.AbstractFlowlet;
import co.cask.cdap.api.flow.flowlet.OutputEmitter;
import co.cask.cdap.api.service.http.AbstractHttpServiceHandler;
import co.cask.cdap.api.service.http.HttpServiceRequest;
import co.cask.cdap.api.service.http.HttpServiceResponder;
import com.google.common.base.Charsets;
import com.google.common.collect.Lists;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
/**
* An application for testing bytecode generated classes ClassLoading behavior.
* In specific, it tests DatumWriter in Flow and HttpHandler in Service.
*/
public class ClassLoaderTestApp extends AbstractApplication {
@Override
public void configure() {
createDataset("records", KeyValueTable.class);
addFlow(new BasicFlow());
addService("RecordQuery", new RecordQueryHandler());
}
/**
* A dummy record class for verification of DatumWriter generation.
*/
public static final class Record {
public enum Type {
PUBLIC, PRIVATE
}
private Type type;
public Record(Type type) {
this.type = type;
}
public Record(String type) {
this.type = Type.valueOf(type.toUpperCase());
}
public Type getType() {
return type;
}
}
public static final class BasicFlow extends AbstractFlow {
@Override
protected void configureFlow() {
setName("BasicFlow");
setDescription("BasicFlow");
addFlowlet(new Source());
addFlowlet(new Sink());
connect(new Source(), new Sink());
}
}
public static final class Source extends AbstractFlowlet {
private OutputEmitter<List<Record>> output;
private Random random = new Random();
@Tick(delay = 1L, unit = TimeUnit.MILLISECONDS)
public void generate() {
// Emit PUBLIC or PRIVATE type randomly
List<Record> records = Lists.newArrayList();
for (int i = 0; i < 10; i++) {
records.add(new Record(Record.Type.values()[random.nextInt(Record.Type.values().length)]));
}
output.emit(records);
}
}
public static final class Sink extends AbstractFlowlet {
@UseDataSet("records")
private KeyValueTable records;
@ProcessInput
public void process(List<Record> inputs) {
for (Record record : inputs) {
records.increment(Bytes.toBytes(record.getType().name()), 1L);
}
}
}
public static final class RecordQueryHandler extends AbstractHttpServiceHandler {
@UseDataSet("records")
private KeyValueTable records;
@GET
@Path("/query")
public void query(HttpServiceRequest request,
HttpServiceResponder responder, @QueryParam("type") Record record) {
long count = Bytes.toLong(records.read(Bytes.toBytes(record.getType().name())));
responder.sendString(200, Long.toString(count), Charsets.UTF_8);
}
}
}