I'm having problems to resolve an issue. First I have an abstract class inheriting from RecursiveTask:
public abstract class GeneratorTaskBase<T, U extends RecursiveTask<T>> extends RecursiveTask<T> {
#Override
protected T compute() {
LOG.debug("Computing: start={}, end={}", start, end);
if (end - start <= THRESHOLD) {
try {
return process();
} catch (Exception e) {
throw new RuntimeException(e);
}
} else {
final int mid = start + (end - start) / 2;
final U leftTask = getTask(start, mid);
final U rightTask = getTask(mid, end);
leftTask.fork();
rightTask.fork();
final T leftResult = leftTask.join();
final T rightResult = rightTask.join();
return getResult(leftResult, rightResult);
}
}
protected abstract T getResult(T leftResult, T rightResult);
protected abstract T process() throws Exception;
protected abstract U getTask(final int start, final int end);
protected abstract String generate();
}
A subclass
public class SqlGenerator extends GeneratorTaskBase<String, SqlGenerator> {
#Override
public String generate() {
this.end = this.files.size();
return this.invoke();
}
#Override
protected SqlGenerator getTask(final int start, final int end) {
return new SqlGenerator(this.path).files(files).start(start).end(end);
}
}
I'm making the call for the task like this:
public final class CsvAsSqlDataProcessor implements
DataProcessor<String, FileInput>
#Override
public void process(FileInput input) {
final String fileName = input.source().getName();
final String directory = input.getDirectory();
LOG.debug("directory: {}", directory);
try {
final CSVReader reader = new CSVReader(new FileReader(directory
.concat(File.separator).concat(fileName)),
SEMICOLON_DELIMETER);
final List<String[]> rows = reader.readAll();
reader.close();
fullInsertStatement = new InsertSqlGenerator(rows, input.source())
.generate();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
When I run it I'm getting the exception:
Exception in thread "main" java.lang.ClassCastException: java.lang.Thread cannot be cast to java.util.concurrent.ForkJoinWorkerThread
at java.util.concurrent.ForkJoinTask.fork(ForkJoinTask.java:622)
at com.bosch.mome.importer.batch.export.sql.GeneratorTaskBase.compute(GeneratorTaskBase.java:40)
at java.util.concurrent.RecursiveTask.exec(RecursiveTask.java:93)
at java.util.concurrent.ForkJoinTask.doInvoke(ForkJoinTask.java:377)
at java.util.concurrent.ForkJoinTask.invoke(ForkJoinTask.java:654)
at com.bosch.mome.importer.batch.export.sql.SqlGenerator.generate(SqlGenerator.java:69)
Can anybody give a hint about what I'm doing wrong?
I solved like this:
#Override
public String generate() {
this.end = this.files.size();
ForkJoinPool pool = new ForkJoinPool();
pool.execute(this);
return this.join();
}
Related
I would like to modify the damage suffered with the enchant protection using the NMS. I wrote below the class of the method I used but it doesn't work, what did I do wrong?
import net.minecraft.server.v1_12_R1.*;
public class EnchantProtectionCustom extends EnchantmentProtection {
public EnchantProtectionCustom(EnchantmentProtection.DamageType var2) {
super(Rarity.COMMON, var2, EnumItemSlot.HEAD, EnumItemSlot.CHEST, EnumItemSlot.LEGS, EnumItemSlot.FEET);
}
#Override
public int a(int var1) {
return this.a.b() + (var1 - 1) * this.a.c() * 100;
}
#Override
public int b(int var1) {
return this.a(var1) + this.a.c() * 100;
}
#Override
public int getMaxLevel() {
return 100;
}
#Override
public boolean canEnchant(ItemStack item) {
return true; // allow for all item
}
}
I then called this method in the onEnable()
public void loadProtection() {
try {
Enchantment enchantmentToChange = Enchantment.PROTECTION_ENVIRONMENTAL;
EnchantProtectionCustom protection = new EnchantProtectionCustom(EnchantmentProtection.DamageType.ALL);
net.minecraft.server.v1_12_R1.Enchantment.enchantments.a(0, new MinecraftKey("protection"), protection);
CraftEnchantment newEnchant = new CraftEnchantment(protection);
Field byNameField = Enchantment.class.getDeclaredField("byName");
byNameField.setAccessible(true);
Map<String, Enchantment> byName = (Map<String, Enchantment>) byNameField.get(null);
byName.put(enchantmentToChange.getName(), newEnchant);
Field byIdField = Enchantment.class.getDeclaredField("byId");
byIdField.setAccessible(true);
Map<Integer, Enchantment> byId = (Map<Integer, Enchantment>) byIdField.get(null);
byId.put(enchantmentToChange.getId(), newEnchant);
} catch (Exception e) {
e.printStackTrace();
}
}
I am trying to write an unbounded ping pipeline that takes output from a ping command and parses it to determine some statistics about the RTT (avg/min/max) and for now, just print the results.
I have already written an unbounded ping source that outputs each line as it comes in. The results are windowed every second for every 5 seconds of pings. The windowed data is fed to a Combine.globally call to statefully process the string outputs. The problem is that the accumulators are never merged and the output is never extracted. This means that the pipeline never continues past this point. What am I doing wrong here?
public class TestPingIPs {
public static void main(String[] args)
{
PipelineOptions options = PipelineOptionsFactory.create();
Pipeline pipeline = Pipeline.create(options);
String destination = "8.8.8.8";
PCollection<PingResult> res =
/*
Run the unbounded ping command. Only the lines where the result of the ping command are returned.
No statistics or first startup lines are returned here.
*/
pipeline.apply("Ping command",
PingCmd.read()
.withPingArguments(PingCmd.PingArguments.create(destination, -1)))
/*
Window the ping command strings into 5 second sliding windows produced every 1 second
*/
.apply("Window strings",
Window.into(SlidingWindows.of(Duration.standardSeconds(5))
.every(Duration.standardSeconds(1))))
/*
Parse and aggregate the strings into a PingResult object using stateful processing.
*/
.apply("Combine the pings",
Combine.globally(new ProcessPings()).withoutDefaults())
/*
Test our output to see what we get here
*/
.apply("Test output",
ParDo.of(new DoFn<PingResult, PingResult>() {
#ProcessElement
public void processElement(ProcessContext c)
{
System.out.println(c.element().getAvgRTT());
System.out.println(c.element().getPacketLoss());
c.output(c.element());
}
}));
pipeline.run().waitUntilFinish();
}
static class ProcessPings extends Combine.CombineFn<String, RttStats, PingResult> {
private long getRTTFromLine(String line){
long rtt = Long.parseLong(line.split("time=")[1].split("ms")[0]);
return rtt;
}
#Override
public RttStats createAccumulator()
{
return new RttStats();
}
#Override
public RttStats addInput(RttStats mutableAccumulator, String input)
{
mutableAccumulator.incTotal();
if (input.contains("unreachable")) {
_unreachableCount.inc();
mutableAccumulator.incPacketLoss();
}
else if (input.contains("General failure")) {
_transmitFailureCount.inc();
mutableAccumulator.incPacketLoss();
}
else if (input.contains("timed out")) {
_timeoutCount.inc();
mutableAccumulator.incPacketLoss();
}
else if (input.contains("could not find")) {
_unknownHostCount.inc();
mutableAccumulator.incPacketLoss();
}
else {
_successfulCount.inc();
mutableAccumulator.add(getRTTFromLine(input));
}
return mutableAccumulator;
}
#Override
public RttStats mergeAccumulators(Iterable<RttStats> accumulators)
{
Iterator<RttStats> iter = accumulators.iterator();
if (!iter.hasNext()){
return createAccumulator();
}
RttStats running = iter.next();
while (iter.hasNext()){
RttStats next = iter.next();
running.addAll(next.getVals());
running.addLostPackets(next.getLostPackets());
}
return running;
}
#Override
public PingResult extractOutput(RttStats stats)
{
stats.calculate();
boolean connected = stats.getPacketLoss() != 1;
return new PingResult(connected, stats.getAvg(), stats.getMin(), stats.getMax(), stats.getPacketLoss());
}
private final Counter _successfulCount = Metrics.counter(ProcessPings.class, "Successful pings");
private final Counter _unknownHostCount = Metrics.counter(ProcessPings.class, "Unknown hosts");
private final Counter _transmitFailureCount = Metrics.counter(ProcessPings.class, "Transmit failures");
private final Counter _timeoutCount = Metrics.counter(ProcessPings.class, "Timeouts");
private final Counter _unreachableCount = Metrics.counter(ProcessPings.class, "Unreachable host");
}
I would guess that there are some issues with the CombineFn that I wrote, but I can't seem to figure out what's going wrong here! I tried following the example here, but there's still something I must be missing.
EDIT: I added the ping command implementation below. This is running on a Direct Runner while I test.
PingCmd.java:
public class PingCmd {
public static Read read(){
if (System.getProperty("os.name").startsWith("Windows")) {
return WindowsPingCmd.read();
}
else{
return null;
}
}
WindowsPingCmd.java:
public class WindowsPingCmd extends PingCmd {
private WindowsPingCmd()
{
}
public static PingCmd.Read read()
{
return new WindowsRead.Builder().build();
}
static class PingCheckpointMark implements UnboundedSource.CheckpointMark, Serializable {
#VisibleForTesting
Instant oldestMessageTimestamp = Instant.now();
#VisibleForTesting
transient List<String> outputs = new ArrayList<>();
public PingCheckpointMark()
{
}
public void add(String message, Instant timestamp)
{
if (timestamp.isBefore(oldestMessageTimestamp)) {
oldestMessageTimestamp = timestamp;
}
outputs.add(message);
}
#Override
public void finalizeCheckpoint()
{
oldestMessageTimestamp = Instant.now();
outputs.clear();
}
// set an empty list to messages when deserialize
private void readObject(java.io.ObjectInputStream stream)
throws IOException, ClassNotFoundException
{
stream.defaultReadObject();
outputs = new ArrayList<>();
}
#Override
public boolean equals(#Nullable Object other)
{
if (other instanceof PingCheckpointMark) {
PingCheckpointMark that = (PingCheckpointMark) other;
return Objects.equals(this.oldestMessageTimestamp, that.oldestMessageTimestamp)
&& Objects.deepEquals(this.outputs, that.outputs);
}
else {
return false;
}
}
}
#VisibleForTesting
static class UnboundedPingSource extends UnboundedSource<String, PingCheckpointMark> {
private final WindowsRead spec;
public UnboundedPingSource(WindowsRead spec)
{
this.spec = spec;
}
#Override
public UnboundedReader<String> createReader(
PipelineOptions options, PingCheckpointMark checkpointMark)
{
return new UnboundedPingReader(this, checkpointMark);
}
#Override
public List<UnboundedPingSource> split(int desiredNumSplits, PipelineOptions options)
{
// Don't really need to ever split the ping source, so we should just have one per destination
return Collections.singletonList(new UnboundedPingSource(spec));
}
#Override
public void populateDisplayData(DisplayData.Builder builder)
{
spec.populateDisplayData(builder);
}
#Override
public Coder<PingCheckpointMark> getCheckpointMarkCoder()
{
return SerializableCoder.of(PingCheckpointMark.class);
}
#Override
public Coder<String> getOutputCoder()
{
return StringUtf8Coder.of();
}
}
#VisibleForTesting
static class UnboundedPingReader extends UnboundedSource.UnboundedReader<String> {
private final UnboundedPingSource source;
private String current;
private Instant currentTimestamp;
private final PingCheckpointMark checkpointMark;
private BufferedReader processOutput;
private Process process;
private boolean finishedPings;
private int maxCount = 5;
private static AtomicInteger currCount = new AtomicInteger(0);
public UnboundedPingReader(UnboundedPingSource source, PingCheckpointMark checkpointMark)
{
this.finishedPings = false;
this.source = source;
this.current = null;
if (checkpointMark != null) {
this.checkpointMark = checkpointMark;
}
else {
this.checkpointMark = new PingCheckpointMark();
}
}
#Override
public boolean start() throws IOException
{
WindowsRead spec = source.spec;
String cmd = createCommand(spec.pingConfiguration().getPingCount(), spec.pingConfiguration().getDestination());
try {
ProcessBuilder builder = new ProcessBuilder(cmd.split(" "));
builder.redirectErrorStream(true);
process = builder.start();
processOutput = new BufferedReader(new InputStreamReader(process.getInputStream()));
return advance();
} catch (Exception e) {
throw new IOException(e);
}
}
private String createCommand(int count, String dest){
StringBuilder builder = new StringBuilder("ping");
String countParam = "";
if (count <= 0){
countParam = "-t";
}
else{
countParam += "-n " + count;
}
return builder.append(" ").append(countParam).append(" ").append(dest).toString();
}
#Override
public boolean advance() throws IOException
{
String line = processOutput.readLine();
// Ignore empty/null lines
if (line == null || line.isEmpty()) {
line = processOutput.readLine();
}
// Ignore the 'Pinging <dest> with 32 bytes of data' line
if (line.contains("Pinging " + source.spec.pingConfiguration().getDestination())) {
line = processOutput.readLine();
}
// If the pings have finished, ignore
if (finishedPings) {
return false;
}
// If this is the start of the statistics, the pings are done and we can just exit
if (line.contains("statistics")) {
finishedPings = true;
}
current = line;
currentTimestamp = Instant.now();
checkpointMark.add(current, currentTimestamp);
if (currCount.incrementAndGet() == maxCount){
currCount.set(0);
return false;
}
return true;
}
#Override
public void close() throws IOException
{
if (process != null) {
process.destroy();
if (process.isAlive()) {
process.destroyForcibly();
}
}
}
#Override
public Instant getWatermark()
{
return checkpointMark.oldestMessageTimestamp;
}
#Override
public UnboundedSource.CheckpointMark getCheckpointMark()
{
return checkpointMark;
}
#Override
public String getCurrent()
{
if (current == null) {
throw new NoSuchElementException();
}
return current;
}
#Override
public Instant getCurrentTimestamp()
{
if (current == null) {
throw new NoSuchElementException();
}
return currentTimestamp;
}
#Override
public UnboundedPingSource getCurrentSource()
{
return source;
}
}
public static class WindowsRead extends PingCmd.Read {
private final PingArguments pingConfig;
private WindowsRead(PingArguments pingConfig)
{
this.pingConfig = pingConfig;
}
public Builder builder()
{
return new WindowsRead.Builder(this);
}
PingArguments pingConfiguration()
{
return pingConfig;
}
public WindowsRead withPingArguments(PingArguments configuration)
{
checkArgument(configuration != null, "configuration can not be null");
return builder().setPingArguments(configuration).build();
}
#Override
public PCollection<String> expand(PBegin input)
{
org.apache.beam.sdk.io.Read.Unbounded<String> unbounded =
org.apache.beam.sdk.io.Read.from(new UnboundedPingSource(this));
return input.getPipeline().apply(unbounded);
}
#Override
public void populateDisplayData(DisplayData.Builder builder)
{
super.populateDisplayData(builder);
pingConfiguration().populateDisplayData(builder);
}
static class Builder {
private PingArguments config;
Builder()
{
}
private Builder(WindowsRead source)
{
this.config = source.pingConfiguration();
}
WindowsRead.Builder setPingArguments(PingArguments config)
{
this.config = config;
return this;
}
WindowsRead build()
{
return new WindowsRead(this.config);
}
}
#Override
public int hashCode()
{
return Objects.hash(pingConfig);
}
}
One thing I notice in your code is that advance() always returns True. The watermark only advances on bundle completion, and I think it's runner-dependent whether a runner will ever complete a bundle if advance ever never returns False. You could try returning False after a bounded amount of time/number of pings.
You could also consider re-writing this as an SDF.
I was recently learning Room Database but this code seems too weird.
I tried to understand this line of code but maybe my google search skill isn't that good.
Can you explain this?
public abstract NoDoDao noDoDao();
The thing I don't understand, how Interface which is 'NoDoDa' here, can be called as if it were 'method' or 'function'? This is my first time seeing this syntax. And why is there also 'Abstract keyword'?
package com.paige.room.data;
import android.content.Context;
import android.os.AsyncTask;
import androidx.annotation.NonNull;
import androidx.room.Database;
import androidx.room.Room;
import androidx.room.RoomDatabase;
import androidx.sqlite.db.SupportSQLiteDatabase;
import com.paige.room.model.NoDo;
#Database(entities = {NoDo.class}, version = 1)
public abstract class NoDoRoomDatabase extends RoomDatabase {
//Don't want to create a lot of instances, singleton
//volatile means "don't store in the cache"
private static volatile NoDoRoomDatabase INSTANCE;
public abstract NoDoDao noDoDao();
public static NoDoRoomDatabase getDatabase(final Context context){
if(INSTANCE == null){
//synchronized keyword, for UI Thread, force it to work as it is supposed to do
synchronized (NoDoRoomDatabase.class){
if(INSTANCE == null){
//create our db
INSTANCE = Room.databaseBuilder(
context,
NoDoRoomDatabase.class,
"nodo_database")
.addCallback(roomDatabaseCallBack)
.build();
}
}
}
return INSTANCE;
}
//callback
private static RoomDatabase.Callback roomDatabaseCallBack =
new RoomDatabase.Callback(){
#Override
public void onOpen(#NonNull SupportSQLiteDatabase db) {
super.onOpen(db);
new PopulateDBAsync(INSTANCE).execute();
}
};
private static class PopulateDBAsync extends AsyncTask<Void, Void, Void> {
private final NoDoDao noDoDao;
PopulateDBAsync(NoDoRoomDatabase db) {
this.noDoDao = db.noDoDao();
}
#Override
protected Void doInBackground(Void... voids) {
// noDoDao.deleteAll(); //removes all items from our table
// //for testing
// NoDo noDo = new NoDo("Buy a new Ferrari");
// noDoDao.insert(noDo);
//
// noDo = new NoDo("Buy a Big House");
// noDoDao.insert(noDo);
return null;
}
}
}
This is my entire code
NoDoDao is an abstract class, it cannot be instantiated (constructed) but the class can be used. Which is what is happening here.
What you may not be aware of is that Room generates code and it is these abstractions that allow the underlying code to be implemented on your behalf.
Say for example that you Entity class NoDO is :-
#Entity
public class NoDo {
#PrimaryKey
Long id;
}
And your Dao class NoDoDao is :-
#Dao
public abstract class NoDoDao {
#Query("SELECT * FROM nodo")
abstract List<NoDo> getnothing();
}
And you compile (F9) then you get :-
Looking at NoDoDao_Impl then you get :-
public final class NoDoDao_Impl extends NoDoDao {
private final RoomDatabase __db;
public NoDoDao_Impl(RoomDatabase __db) {
this.__db = __db;
}
#Override
List<NoDo> getnothing() {
final String _sql = "SELECT * FROM nodo";
final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, 0);
__db.assertNotSuspendingTransaction();
final Cursor _cursor = DBUtil.query(__db, _statement, false, null);
try {
final int _cursorIndexOfId = CursorUtil.getColumnIndexOrThrow(_cursor, "id");
final List<NoDo> _result = new ArrayList<NoDo>(_cursor.getCount());
while(_cursor.moveToNext()) {
final NoDo _item;
_item = new NoDo();
if (_cursor.isNull(_cursorIndexOfId)) {
_item.id = null;
} else {
_item.id = _cursor.getLong(_cursorIndexOfId);
}
_result.add(_item);
}
return _result;
} finally {
_cursor.close();
_statement.release();
}
}
}
That is the real getNothing code has been generated by the annotation processor.
As important is that the NoDoRoomDatabase_Impl is :-
public final class NoDoRoomDatabase_Impl extends NoDoRoomDatabase {
private volatile NoDoDao _noDoDao;
#Override
protected SupportSQLiteOpenHelper createOpenHelper(DatabaseConfiguration configuration) {
final SupportSQLiteOpenHelper.Callback _openCallback = new RoomOpenHelper(configuration, new RoomOpenHelper.Delegate(1) {
#Override
public void createAllTables(SupportSQLiteDatabase _db) {
_db.execSQL("CREATE TABLE IF NOT EXISTS `NoDo` (`id` INTEGER, PRIMARY KEY(`id`))");
_db.execSQL("CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)");
_db.execSQL("INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '1fdde93d9c60610ae88bf0c74771844a')");
}
#Override
public void dropAllTables(SupportSQLiteDatabase _db) {
_db.execSQL("DROP TABLE IF EXISTS `NoDo`");
if (mCallbacks != null) {
for (int _i = 0, _size = mCallbacks.size(); _i < _size; _i++) {
mCallbacks.get(_i).onDestructiveMigration(_db);
}
}
}
#Override
protected void onCreate(SupportSQLiteDatabase _db) {
if (mCallbacks != null) {
for (int _i = 0, _size = mCallbacks.size(); _i < _size; _i++) {
mCallbacks.get(_i).onCreate(_db);
}
}
}
#Override
public void onOpen(SupportSQLiteDatabase _db) {
mDatabase = _db;
internalInitInvalidationTracker(_db);
if (mCallbacks != null) {
for (int _i = 0, _size = mCallbacks.size(); _i < _size; _i++) {
mCallbacks.get(_i).onOpen(_db);
}
}
}
#Override
public void onPreMigrate(SupportSQLiteDatabase _db) {
DBUtil.dropFtsSyncTriggers(_db);
}
#Override
public void onPostMigrate(SupportSQLiteDatabase _db) {
}
#Override
protected RoomOpenHelper.ValidationResult onValidateSchema(SupportSQLiteDatabase _db) {
final HashMap<String, TableInfo.Column> _columnsNoDo = new HashMap<String, TableInfo.Column>(1);
_columnsNoDo.put("id", new TableInfo.Column("id", "INTEGER", false, 1, null, TableInfo.CREATED_FROM_ENTITY));
final HashSet<TableInfo.ForeignKey> _foreignKeysNoDo = new HashSet<TableInfo.ForeignKey>(0);
final HashSet<TableInfo.Index> _indicesNoDo = new HashSet<TableInfo.Index>(0);
final TableInfo _infoNoDo = new TableInfo("NoDo", _columnsNoDo, _foreignKeysNoDo, _indicesNoDo);
final TableInfo _existingNoDo = TableInfo.read(_db, "NoDo");
if (! _infoNoDo.equals(_existingNoDo)) {
return new RoomOpenHelper.ValidationResult(false, "NoDo(a.so59478461.NoDo).\n"
+ " Expected:\n" + _infoNoDo + "\n"
+ " Found:\n" + _existingNoDo);
}
return new RoomOpenHelper.ValidationResult(true, null);
}
}, "1fdde93d9c60610ae88bf0c74771844a", "1d145662ebde2538a8da3217996c0550");
final SupportSQLiteOpenHelper.Configuration _sqliteConfig = SupportSQLiteOpenHelper.Configuration.builder(configuration.context)
.name(configuration.name)
.callback(_openCallback)
.build();
final SupportSQLiteOpenHelper _helper = configuration.sqliteOpenHelperFactory.create(_sqliteConfig);
return _helper;
}
#Override
protected InvalidationTracker createInvalidationTracker() {
final HashMap<String, String> _shadowTablesMap = new HashMap<String, String>(0);
HashMap<String, Set<String>> _viewTables = new HashMap<String, Set<String>>(0);
return new InvalidationTracker(this, _shadowTablesMap, _viewTables, "NoDo");
}
#Override
public void clearAllTables() {
super.assertNotMainThread();
final SupportSQLiteDatabase _db = super.getOpenHelper().getWritableDatabase();
try {
super.beginTransaction();
_db.execSQL("DELETE FROM `NoDo`");
super.setTransactionSuccessful();
} finally {
super.endTransaction();
_db.query("PRAGMA wal_checkpoint(FULL)").close();
if (!_db.inTransaction()) {
_db.execSQL("VACUUM");
}
}
}
#Override
public NoDoDao noDoDao() {
if (_noDoDao != null) {
return _noDoDao;
} else {
synchronized(this) {
if(_noDoDao == null) {
_noDoDao = new NoDoDao_Impl(this);
}
return _noDoDao;
}
}
}
}
See how NoDoDao has been overridden to basically be NoDoDao_Impl
I try to make a thread safe class which allows to follow the scan of something. My class is:
import java.util.concurrent.atomic.AtomicInteger;
public class ScanInProgress {
private final Integer scanId;
private final int nbScans;
private AtomicInteger nbResponses = new AtomicInteger(0);
private AtomicInteger nbErrors = new AtomicInteger(0);
public ScanInProgress(Integer scanId, int nbSites) {
this.scanId = scanId;
this.nbScans = nbSites;
}
public Integer getScanId() {
return scanId;
}
public boolean addSuccess() {
addResponse();
return isDone();
}
public boolean addError() {
addResponse();
nbErrors.incrementAndGet();
return isDone();
}
private void addResponse() {
nbResponses.incrementAndGet();
}
private boolean isDone() {
return nbResponses.get() == nbScans;
}
public int getNbSuccesses() {
return nbResponses.get() - nbErrors.get();
}
public int getNbResponses() {
return nbResponses.get();
}
}
I have the following unit tests class:
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
public class ScanInProgressTest {
#Test
public void testConcurrency() throws Exception {
// given
Integer scanId = 1;
int nbScans = 500_000;
ScanInProgress scanInProgress = new ScanInProgress(scanId, nbScans);
// when
for (int i = 1; i <= nbScans / 2; i++) {
new AddError(scanInProgress).start();
new AddSuccess(scanInProgress).start();
}
Thread.sleep(1000);
// then
assertEquals(nbScans, scanInProgress.getNbResponses());
assertEquals(nbScans / 2, scanInProgress.getNbSuccesses());
}
private class AddError extends Thread {
private ScanInProgress scanInProgress;
public AddError(ScanInProgress scanInProgress) {
this.scanInProgress = scanInProgress;
}
#Override
public void run() {
int before = scanInProgress.getNbResponses();
scanInProgress.addError();
int after = scanInProgress.getNbResponses();
assertTrue("Add error: before=" + before + ", after=" + after, before < after);
}
}
private class AddSuccess extends Thread {
private ScanInProgress scanInProgress;
public AddSuccess(ScanInProgress scanInProgress) {
this.scanInProgress = scanInProgress;
}
#Override
public void run() {
int beforeResponses = scanInProgress.getNbResponses();
int beforeSuccesses = scanInProgress.getNbSuccesses();
scanInProgress.addSuccess();
int afterResponses = scanInProgress.getNbResponses();
int afterSuccesses = scanInProgress.getNbSuccesses();
assertTrue("Add success responses: before=" + beforeResponses + ", after=" + afterResponses, beforeResponses < afterResponses);
assertTrue("Add success successes: before=" + beforeSuccesses + ", after=" + afterSuccesses, beforeSuccesses < afterSuccesses);
}
}
}
When I run my test I can see regularly this error in logs:
Exception in thread "Thread-14723" java.lang.AssertionError: Add success successes: before=7362, after=7362
at org.junit.Assert.fail(Assert.java:88)
at org.junit.Assert.assertTrue(Assert.java:41)
The assertion lets me think that when I call the method scanInProgress.addSuccess() and then scanInProgress.getNbSuccesses(), the instruction in first method nbResponses.incrementAndGet() is not yet acknowledged whereas the instruction in second method nbResponses.get() returns something.
What can I do to correct this ?
As far as I unsterstand the problem I think you need to use locks. Before you get or set an variable you need to aquire a lock. This way a variable can't be set and read at the same time. You get something like the code below.
public final static Object LOCK = new Object();
private int yourvariable;
public void setVar(int var){
synchronized(LOCK){
yourvariable = var;
}
}
public int getVar(){
int toReturn;
synchronized(LOCK){
toReturn = yourvariable;
}
return toReturn;
}
note: If your ScanInProgessClass is the only the ScanInProgressClass class, you can use this instead of a LOCK object.
I was trying to do a simple implementation of the command patter in java. However, I am getting the following error:
java.lang.ClassNotFoundException: AddCommand
Exception in thread "main" java.lang.NullPointerException
at com.programming.sample.TransactionCommand.execute(TestTransactionCommand.java:64)
at com.programming.sample.CommandManager.runCommands(TestTransactionCommand.java:33)
at com.programming.sample.TestTransactionCommand.main(TestTransactionCommand.java:124)
Code:
package com.programming.sample;
//TestTransactionCommand.java
import java.util.*;
final class CommandReceiver {
private int[] c;
private CommandArgument a;
private CommandReceiver(){
c = new int[2];
}
private static CommandReceiver cr = new CommandReceiver();
public static CommandReceiver getHandle() {
return cr;
}
public void setCommandArgument(CommandArgument a) {
this.a = a;
}
public void methAdd() {
c = a.getArguments();
System.out.println("The result is " + (c[0]+c[1]));
}
public void methSubtract() {
c = a.getArguments();
System.out.println("The result is " + (c[0]-c[1]));
}
}
class CommandManager {
private Command myCommand;
public CommandManager(Command myCommand) {
this.myCommand = myCommand ;
}
public void runCommands( ) {
myCommand.execute();
}
}
class TransactionCommand implements Command {
private CommandReceiver commandreceiver;
private Vector commandnamelist,commandargumentlist;
private String commandname;
private CommandArgument commandargument;
private Command command;
public TransactionCommand () {
this(null,null);
}
public TransactionCommand ( Vector commandnamelist, Vector
commandargumentlist){
this.commandnamelist = commandnamelist;
this.commandargumentlist = commandargumentlist;
commandreceiver = CommandReceiver.getHandle();
}
public void execute( ) {
for (int i = 0; i < commandnamelist.size(); i++) {
commandname = (String)(commandnamelist.get(i));
commandargument = (CommandArgument)((commandargumentlist.get(i)));
commandreceiver.setCommandArgument(commandargument);
String classname = commandname + "Command";
try {
Class cls = Class.forName(classname);
command = (Command) cls.newInstance();
}
catch (Throwable e) {
System.err.println(e);
}
command.execute();
}
}
}
class AddCommand extends TransactionCommand {
private CommandReceiver cr;
public AddCommand () {
cr = CommandReceiver.getHandle();
}
public void execute( ) {
cr.methAdd();
}
}
class SubtractCommand extends TransactionCommand {
private CommandReceiver cr;
public SubtractCommand () {
cr = CommandReceiver.getHandle();
}
public void execute( ) {
cr.methSubtract();
}
}
class CommandArgument {
private int[] args;
CommandArgument() {
args = new int[2];
}
public int[] getArguments() {
return args;
}
public void setArgument(int i1, int i2) {
args[0] = i1; args[1] = i2;
}
}
public class TestTransactionCommand {
private Vector clist,alist;
public TestTransactionCommand() {
clist = new Vector();
alist = new Vector();
}
public void clearBuffer(Vector c, Vector a) {
clist.removeAll(c);
alist.removeAll(a);
}
public Vector getClist() {
return clist;
}
public Vector getAlist() {
return alist;
}
public static void main(String[] args) {
CommandArgument ca,ca2;
TestTransactionCommand t = new TestTransactionCommand();
ca = new CommandArgument();
ca.setArgument(2,8);
Vector myclist = t.getClist();
Vector myalist = t.getAlist();
myclist.addElement("Add");
myalist.addElement(ca);
TransactionCommand tc = new TransactionCommand(myclist,myalist);
CommandManager cm = new CommandManager(tc);
cm.runCommands();
t.clearBuffer(myclist,myalist);
ca2 = new CommandArgument();
ca2.setArgument(5,7);
myclist = t.getClist();
myalist = t.getAlist();
myclist.addElement("Subtract");
myalist.addElement(ca2);
myclist.addElement("Add");
myalist.addElement(ca2);
TransactionCommand tc2 = new TransactionCommand(myclist,myalist);
CommandManager cm2 = new CommandManager(tc2);
cm2.runCommands();
}
}
I guess, this is where it's failing.
try {
Class cls = Class.forName(classname);
command = (Command) cls.newInstance();
}
catch (Throwable e) {
System.err.println(e);
}
command.execute();
Obviously, the class AddCommand wasn't found in the classpath, so it resulted in the ClassNotFoundException, which you ignored with just System.err.println(e); and then trying to invoke command.execute();. The object command isn't initialized to an instance.
Perhaps, providing the full class name, like, com.programming.sample.AddCommand, would fix it.
When you create the classname, the string contains only AddCommand. The class' actual name is com.programming.sample.AddCommand.
I can't compile your code - there is no Command interface.
With simple
interface Command {
public void execute();
}
your code compiles fine just with warning:
Note: D:\dev\puzzles\TestTransactionCommand.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.