I have this Java code:
public class TestMapper extends AppEngineMapper<Key, Entity, NullWritable, NullWritable> {
public TestMapper() {
}
// [... other overriden methods ...]
#Override
public void setup(Context context) {
log.warning("Doing per-worker setup");
}
}
...which I've converted to:
class TestMapper extends AppEngineMapper[Key, Entity, NullWritable, NullWritable] {
// [... other overriden methods ...]
override def setup(context: Context) {
log.warning("Doing per-worker setup")
}
}
Now the actual problem:
Context is defined as a nested class within the org.apache.hadoop.mapreduce.Mapper class:
public static class Mapper<KEYIN, VALUEIN, KEYOUT, VALUEOUT> {
//[... some other methods ...]
protected void setup(org.apache.hadoop.mapreduce.Mapper<KEYIN,VALUEIN,KEYOUT,VALUEOUT>.Context context) throws java.io.IOException, java.lang.InterruptedException { /* compiled code */ }
public class Context extends org.apache.hadoop.mapreduce.MapContext<KEYIN,VALUEIN,KEYOUT,VALUEOUT> {
public Context(org.apache.hadoop.conf.Configuration configuration, org.apache.hadoop.mapreduce.TaskAttemptID conf, org.apache.hadoop.mapreduce.RecordReader<KEYIN,VALUEIN> taskid, org.apache.hadoop.mapreduce.RecordWriter<KEYOUT,VALUEOUT> reader, org.apache.hadoop.mapreduce.OutputCommitter writer, org.apache.hadoop.mapreduce.StatusReporter committer, org.apache.hadoop.mapreduce.InputSplit reporter) throws java.io.IOException, java.lang.InterruptedException { /* compiled code */ }
}
So I can't tell my Scala class where/what Context actually is. If Mapper had no generics I could reference Context via
Mapper#Context
but how can I tell that Mapper has Generics?
Mapper[_,_,_,_]#Context
...didn't work.
You have to supply the exact base type for your type projection, in your case
Mapper[Key, Entity, NullWritable, NullWritable]#Context
so overriding setup would be written as
override def setup(context: Mapper[Key, Entity, NullWritable, NullWritable]#Context)
Usage can be simplified by introducing a type alias
class TestMapper extends AppEngineMapper[Key, Entity, NullWritable, NullWritable] {
type Context = Mapper[Key, Entity, NullWritable, NullWritable]#Context
override def setup(context: Context) = {
// ...
}
}
If you want to write multiple mappers you can refactor this into a trait that can be mixed into your implementation:
trait SMapper[A,B,C,D] extends Mapper[A,B,C,D] {
type Context = Mapper[A,B,C,D]#Context
}
class TestMapper extends AppEngineMapper[Key, Entity, NullWritable, NullWritable]
with SMapper[Key, Entity, NullWritable, NullWritable] {
override def setup(context: Context) = {
// ...
}
}
or for plain hadoop:
class TestMapper extends SMapper[Key, Entity, NullWritable, NullWritable] {
override def setup(context: Context) = {
// ...
}
}
The problems people have sometimes when using the accepted answer are due to a bug in Scala compiler (link).
Related
I am trying to create a generic router whose processor and other attributes are populated from a static class. Here is sample code.
public class GenericRouter extends RouteBuilder( {
#Override
public void configure() throws Exception {
from("direct:generic-route")
.process(Util.getProcesss(“${exchangeProperty[processKey]"))
.ToD(Util.getUrl(“${exchangeProperty[urlKey]"));
}
}
Public class Util{
Map<String,Object> routerResources;
static {
//load routerResources
}
public static Processor getProcessor(String processorKey){
return (Processor)routerResources.get(processorKey);
}
public static Processor getUrl(String urlKey){
return (String)routerResources.get(urlKey);
}
}
The generic router is expected to post a rest call. the properties "urlKey" and "processorUrl" are already available in exchange. I finding it difficult to pass exchange properties to static Util class methods.
If you want to access properties of an exchange in plain java you can use .process or .exchange. If you need to access body or headers you can use e.getMessage().getBody() and e.getMessage().getHeader()
from("direct:generic-route")
.process( e -> {
String processKey = e.getProperty("processKey", String.class);
Processor processor = Util.getProcessor(processKey);
processor.process(e);
})
.setProperty("targetURL").exchange( e -> {
String urlKey = e.getProperty("urlKey", String.class);
return Util.getUrl(urlKey);
})
.toD("${exchangeProperty.targetURL}");
Also make sure you fix the return type of this method:
public static Processor getUrl(String urlKey){
return (String)routerResources.get(urlKey);
}
As a side note, you can actually use map stored in body, header or property through simple language.
public class ExampleTest extends CamelTestSupport {
#Test
public void example(){
template.sendBodyAndHeader("direct:example", null, "urlKey", "urlA");
}
#Override
protected RoutesBuilder createRouteBuilder() throws Exception {
return new RouteBuilder() {
#Override
public void configure() throws Exception {
Map<String, String> urlMap = new HashMap<>();
urlMap.put("urlA", "direct:pointA");
urlMap.put("urlB", "direct:pointB");
from("direct:example")
.setProperty("urlMap").constant(urlMap)
.log("url: ${exchangeProperty.urlMap['${headers.urlKey}']}");
}
};
}
}
I am studying Flink, I want to build an operator function which extends ProcessWindowFunction and overload a new constructor with a parameter as a field value of the class, but when this class is instanced, without of this field, I am confused. code as follow.
import com.aliyun.datahub.client.model.Field;
import com.aliyun.datahub.client.model.FieldType;
import com.aliyun.datahub.client.model.PutRecordsResult;
import io.github.streamingwithflink.chapter8.PoJoElecMeterSource;
import org.apache.flink.streaming.api.TimeCharacteristic;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.windowing.assigners.TumblingProcessingTimeWindows;
import org.apache.flink.streaming.api.windowing.time.Time;
public class DataHubSinkDemo {
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setStreamTimeCharacteristic(TimeCharacteristic.ProcessingTime);
env.enableCheckpointing(10_000L);
env.setParallelism(2);
RecordSchemaSer schema = new RecordSchemaSer();
schema.addField(new Field("id", FieldType.STRING));
DataStream<PutRecordsResult> out = env
.addSource(new PoJoElecMeterSource())
.keyBy( r -> r.getId())
.window(TumblingProcessingTimeWindows.of(Time.seconds(3)))
.process(new PutDatahubFunction<>(schema)); // PutDatahubFunction is my build a new Operator function class
env.execute();
}
}
variable schema is a parameter which I want to send to the constructor, it is an instance of RecordSchemaSer Class
import com.aliyun.datahub.client.model.RecordSchema;
import java.io.Serializable;
public class RecordSchemaSer
extends RecordSchema
implements Serializable {
}
PutDatahubFunction is a class extends ProcessWindowFunction, code as follows
import com.aliyun.datahub.client.model.*;
import io.github.streamingwithflink.chapter8.PUDAPoJo;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.functions.windowing.ProcessWindowFunction;
import org.apache.flink.streaming.api.windowing.windows.TimeWindow;
import org.apache.flink.util.Collector;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
public class PutDatahubFunction<IN extends PUDAPoJo, KEY>
extends ProcessWindowFunction<IN, PutRecordsResult, KEY, TimeWindow> {
private DataHubBase dataHubHandler;
private List<RecordEntry> recordEntries;
private RecordSchema schema;
public PutDatahubFunction(RecordSchema schema) {
this.schema = schema;
System.out.println("field 'id' not exist ? " + this.schema.containsField("id")); // it's true
}
#Override
public void open(Configuration parameters) throws Exception {
.........
}
#Override
public void process(KEY KEY,
Context context,
Iterable<IN> elements,
Collector<PutRecordsResult> out)
throws Exception {
RecordEntry entry = new RecordEntry();
for (IN e : elements) {
System.out.println("field 'id' not exist ? " + this.schema.containsField("id")); // it's false
......
}
}
}
the first system.out in the constructor, this.schema.containsField("id") is true, but the second system.out in process method, this.schema.containsField("id") is false! why? I have system.out two class name of the instance which both are PutDatahubFunction.
use ValueState not working, because constructor not call getRuntimeContext(), otherwise Exception in thread "main" java.lang.IllegalStateException: The runtime context has not been initialized. code as follow:
private ValueState<RecordSchema> schema;
public PutTupleDatahubFunction(RecordSchema schema) throws IOException {
ValueStateDescriptor schemaDes =
new ValueStateDescriptor("datahub schema", TypeInformation.of(RecordSchema.class));
/*
* error Exception in thread "main" java.lang.IllegalStateException:
* The runtime context has not been initialized.
*/
this.schema = getRuntimeContext().getState(schemaDes);
this.schema.update(schema);
}
I am very fuzzing, who can tell me the reason, Is there any way to pass arguments to the constructor of this operator function class? thanks.
I finally figured out why,the reason is Serialize and Deserialize. I am not coding RecordSchemaSer reason is Serialize content, due to null
public class RecordSchemaSer
extends RecordSchema
implements Serializable
{
}
I have mongodb related code in my java application and can I switch between two collections under same db in java code ?
#JsonIgnoreProperties(ignoreUnknown = true)
#Document(collection = "collectionA")
#QueryEntity
public class RepreCase {
I want to have a different collection here instead of this say collectionB #Document(collection = "collectionA") and comeback to the same collectionA, by switching between the two collections A & B under same DB
Can I do like this ? #Document(collection = "collectionA, collectionB")
Is it achievable & How ? Thanks in advance
This example should help
Define your entity class like
#Document(collection = "${EventDataRepository.getCollectionName()}")
public class EventData implements Serializable {
Define a custom repository interface with getter and setter methods for "collectionName"
public interface EventDataRepositoryCustom {
String getCollectionName();
void setCollectionName(String collectionName);
}
Provide implementation class for custom repository with "collectionName" implementation
public class EventDataRepositoryImpl implements EventDataRepositoryCustom{
private static String collectionName = "myCollection";
#Override
public String getCollectionName() {
return collectionName;
}
#Override
public void setCollectionName(String collectionName) {
this.collectionName = collectionName;
}
}
Add EventDataRepositoryImpl to the extends list of your repository interface in this it would look like
#Repository
public interface EventDataRepository extends MongoRepository<EventData, String>, EventDataRepositoryImpl {
}
Now in your Service class where you are using the MongoRepository set the collection name, it would look like
#Autowired
EventDataRepository repository ;
repository.setCollectionName("collectionName");
I am trying to use Spring-AOP/AspectJ on the methods in a class annotated with #Transactional. So, I have two model DAO classes like this:
#Transactional
#Repository
public class ModelDAO {
public void save() {
}
}
#Transactional
#Repository
public class AnotherModelDAO {
public void save() {
}
}
And then an Aspect like:
#Aspect
public class ModelAspect {
#Around("publicMethod() && isModelClassSaveCalled()")
public Object doAspect(ProceedingJoinPoint joinPoint) throws Throwable {
joinPoint.proceed();
anotherModelDAO.save();
}
}
So, my question is: Is it possible to call model.save() and anotherModel.save() to be called in same transaction context through aspect as mentioned above?
Any help will be much appreciated.
Before I setup a test class like the code below:
1. the Factory and test Dataprovider both used excel as the dataprovider.
2. In the Factory dataprovider table, it has a list of url
3. Each time, it will find one of the url in the factory dataprovider table, and run the test in each test methods..
public class Test {
WebDriver driver;
private String hostName;
private String url;
#Factory(dataProvider = "xxxx global variables", dataProviderClass = xxxx.class)
public GetVariables(String hostName, String url) {
this.hostName = hostName;
this.url = url;
}
#BeforeMethod
#Parameters("browser")
public void start(String browser) throws Exception {
driver = new FirefoxDriver();
driver.get(url);
Thread.sleep(1000);
}
#Test(priority = 10, dataProvider = "dataprovider Test A", dataProviderClass = xxx.class)
public void TestA(Variable1,
Variable2,Variable3) throws Exception {
some test here...
}
#Test(priority = 20, dataProvider = "dataprovider Test B", dataProviderClass = xxx.class)
public void TestB(Variable1,
Variable2,Variable3)
throws Exception {
some test here...
}
#AfterMethod
public void tearDown() {
driver.quit();
}
Now I want to dynamically assign different group for each test for different url. I am thinking add a variable 'flag' in the #Factory dataprovider:
#Factory(dataProvider = "xxxx global variables", dataProviderClass = xxxx.class)
public GetVariables(String hostName, String url, String flag) {
this.hostName = hostName;
this.url = url;
this.flag = flag;
}
That when flag.equals("A"), it will only run test cases in test groups={"A"}.
When flag.equals("B"), it will only run test cases in test groups ={"B"},
When flag.equals("A,B"), it will only run test cases in test groups ={"A","B"}
Is there any way I can do that?
Thank you!
TestNG groups provides "flexibility in how you partition your tests" but it isn't for conditional test sets. For that you simply use plain old Java.
You can use inheritance or composition (I recommend the latter, see Item 16: Favor composition over inheritance from Effective Java).
Either way the general idea is the same: use a Factory to create your test class instances dynamically creating the appropriate class type with the appropriate test annotations and/or methods that you want to run.
Examples:
Inheritance
import org.testng.annotations.Factory;
import org.testng.annotations.Test;
public class DemoTest {
#Factory
public static Object[] createTests() {
return new Object[]{
new FlavorATest(),
new FlavorBTest(),
new FlavorABTest()
};
}
/**
* Base test class with code for both A-tests and B-tests.
*
* Note that none of these test methods are annotated as tests so that
* subclasses may pick which ones to annotate.
*/
public static abstract class BaseTest {
protected void testA() {
// test something specific to flavor A
}
protected void testB() {
// test something specific to flavor B
}
}
// extend base but only annotate A-tests
public static class FlavorATest extends BaseTest {
#Test
#Override
public void testA() {
super.testA();
}
}
// extend base but only annotate B-tests
public static class FlavorBTest extends BaseTest {
#Test
#Override
public void testB() {
super.testB();
}
}
// extend base and annotate both A-tests and B-tests
public static class FlavorABTest extends BaseTest {
#Test
#Override
public void testA() {
super.testA();
}
#Test
#Override
public void testB() {
super.testB();
}
}
}
Composition
import org.testng.annotations.Factory;
import org.testng.annotations.Test;
public class DemoTest {
#Factory
public static Object[] createTests() {
return new Object[]{
new FlavorATest(),
new FlavorBTest(),
new FlavorABTest()
};
}
private static void testA() {
// test something specific to flavor A
}
private static void testB() {
// test something specific to flavor B
}
// only create A-test methods and delegate to shared code above
public static class FlavorATest {
#Test
public void testA() {
DemoTest.testA();
}
}
// only create B-test methods and delegate to shared code above
public static class FlavorBTest {
#Test
public void testB() {
DemoTest.testB();
}
}
// create A-test and B-test methods and delegate to shared code above
public static class FlavorABTest {
#Test
public void testA() {
DemoTest.testA();
}
#Test
public void testB() {
DemoTest.testB();
}
}
}
Your factory methods won't be as simple as you'll need to use your "flag" from your test data to switch off of and create instances of the appropriate test classes.