Prechádzať zdrojové kódy

- adding logger to project
- adding banner to project
- adding right available commands for compile
- adding exception handling
- implementing holtek emulator
- moving bin2srcLine array to program model
- SPSassembler working on own string list
- adding stacktrace to websession model

Klaas, Wilfried 6 rokov pred
rodič
commit
72dd5db70e

+ 4 - 1
src/main/java/de/mcs/tools/sps/SPSAssembler.java

@@ -293,6 +293,7 @@ public class SPSAssembler {
     inMacro = false;
     actualMacro = null;
     macros = new HashMap<>();
+    destination = HARDWARE.HOLTEK;
   }
 
   public void doWork(File source) throws IOException, SyntaxError {
@@ -302,7 +303,9 @@ public class SPSAssembler {
     doCompile(sourceFile);
   }
 
-  public void doCompile(List<String> sourceFile) throws SyntaxError, IOException {
+  public void doCompile(List<String> source) throws SyntaxError, IOException {
+    ArrayList<String> sourceFile = new ArrayList<>();
+    sourceFile.addAll(source);
     for (int i = 0; i < sourceFile.size(); i++) {
       String line = sourceFile.get(i);
 

+ 107 - 19
src/main/java/de/mcs/tools/sps/emulator/AbstractEmulator.java

@@ -32,6 +32,7 @@ import de.mcs.tools.sps.emulator.model.WorkingModel;
 import de.mcs.tools.sps.emulator.model.WorkingModel.WORKINGSTATE;
 import de.mcs.tools.sps.exceptions.SyntaxError;
 import de.mcs.tools.sps.mnemonic.Mnemonic;
+import de.mcs.utils.Logger;
 
 /**
  * @author wklaa_000
@@ -39,6 +40,8 @@ import de.mcs.tools.sps.mnemonic.Mnemonic;
  */
 public abstract class AbstractEmulator implements Emulator {
 
+  Logger log = Logger.getLogger(this.getClass());
+
   private WebSessionModel model;
 
   public AbstractEmulator(WebSessionModel model) {
@@ -94,10 +97,101 @@ public abstract class AbstractEmulator implements Emulator {
    */
   @Override
   public boolean next() {
-    // TODO Auto-generated method stub
+    byte commandData = model.getProgram().getBin()[model.getProgram().getActualLine()];
+    log.debug("new command 0x%02x", commandData);
+
+    int command = (commandData & 0xF0);
+    byte data = (byte) (commandData & 0x0F);
+
+    switch (command) {
+    case 0x00:
+      doNop(data);
+      break;
+    case 0x10:
+      doPort(data);
+      break;
+    case 0x20:
+      doDelay(data);
+      break;
+    case 0x30:
+      doJumpBack(data);
+      break;
+    case 0x40:
+      doSetA(data);
+      break;
+    case 0x50:
+      doIsA(data);
+      break;
+    case 0x60:
+      doAIs(data);
+      break;
+    case 0x70:
+      doCalc(data);
+      break;
+    case 0x80:
+      doPage(data);
+      break;
+    case 0x90:
+      doJump(data);
+      break;
+    case 0xA0:
+      doCCount(data);
+      break;
+    case 0xB0:
+      doDCount(data);
+      break;
+    case 0xC0:
+      doSkip(data);
+      break;
+    case 0xD0:
+      doCall(data);
+      break;
+    case 0xE0:
+      doCallSub(data);
+      break;
+    case 0xF0:
+      doByte(data);
+      break;
+
+    default:
+      break;
+    }
+    model.getWork().setAddress((short) (model.getWork().getAddress() + 1));
     return false;
   }
 
+  protected abstract void doSetA(byte data);
+
+  protected abstract void doCalc(byte data);
+
+  protected abstract void doCall(byte data);
+
+  protected abstract void doCCount(byte data);
+
+  protected abstract void doNop(byte data);
+
+  protected abstract void doPort(byte data);
+
+  protected abstract void doDelay(byte data);
+
+  protected abstract void doJumpBack(byte data);
+
+  protected abstract void doAIs(byte data);
+
+  protected abstract void doIsA(byte data);
+
+  protected abstract void doPage(byte data);
+
+  protected abstract void doJump(byte data);
+
+  protected abstract void doDCount(byte data);
+
+  protected abstract void doSkip(byte data);
+
+  protected abstract void doCallSub(byte data);
+
+  protected abstract void doByte(byte data);
+
   @Override
   public boolean stop() {
     model.getWork().setWorkingstate(WORKINGSTATE.NN);
@@ -105,28 +199,22 @@ public abstract class AbstractEmulator implements Emulator {
   }
 
   @Override
-  public boolean compile() {
+  public boolean compile() throws SyntaxError, IOException {
     SPSAssembler spsAssembler = new SPSAssembler();
     List<String> source = Arrays.asList(model.getProgram().getSource());
-    try {
-      spsAssembler.doCompile(source);
-      List<Mnemonic> mnemonics = spsAssembler.getMnemonics();
-      List<Integer> lineNumbers = spsAssembler.getLines();
-      byte[] bin = new byte[mnemonics.size()];
-      int[] bin2SrcLine = new int[mnemonics.size()];
-      for (int i = 0; i < mnemonics.size(); i++) {
-        Mnemonic mnemonic = mnemonics.get(i);
-        bin[i] = (byte) mnemonic.getByte();
-        bin2SrcLine[i] = lineNumbers.get(i);
-      }
-      model.getProgram().setBin(bin);
-      model.getWork().setBin2SrcLine(bin2SrcLine);
-    } catch (SyntaxError | IOException e) {
-      // TODO Auto-generated catch block
-      e.printStackTrace();
+    spsAssembler.doCompile(source);
+    List<Mnemonic> mnemonics = spsAssembler.getMnemonics();
+    List<Integer> lineNumbers = spsAssembler.getLines();
+    byte[] bin = new byte[mnemonics.size()];
+    int[] bin2SrcLine = new int[mnemonics.size()];
+    for (int i = 0; i < mnemonics.size(); i++) {
+      Mnemonic mnemonic = mnemonics.get(i);
+      bin[i] = (byte) mnemonic.getByte();
+      bin2SrcLine[i] = lineNumbers.get(i);
     }
+    model.getProgram().setBin(bin);
+    model.getProgram().setBin2SrcLine(bin2SrcLine);
 
-    List<Mnemonic> mnemonics = spsAssembler.getMnemonics();
     return false;
   }
 

+ 5 - 1
src/main/java/de/mcs/tools/sps/emulator/Emulator.java

@@ -21,6 +21,10 @@
  */
 package de.mcs.tools.sps.emulator;
 
+import java.io.IOException;
+
+import de.mcs.tools.sps.exceptions.SyntaxError;
+
 /**
  * @author wklaa_000
  *
@@ -33,6 +37,6 @@ public interface Emulator {
 
   boolean stop();
 
-  boolean compile();
+  boolean compile() throws SyntaxError, IOException;
 
 }

+ 275 - 0
src/main/java/de/mcs/tools/sps/emulator/holtek/HoltekEmulator.java

@@ -24,6 +24,7 @@ package de.mcs.tools.sps.emulator.holtek;
 import de.mcs.tools.sps.emulator.AbstractEmulator;
 import de.mcs.tools.sps.emulator.Emulator;
 import de.mcs.tools.sps.emulator.model.WebSessionModel;
+import de.mcs.tools.sps.emulator.model.WorkingModel;
 
 /**
  * @author wklaa_000
@@ -31,8 +32,282 @@ import de.mcs.tools.sps.emulator.model.WebSessionModel;
  */
 public class HoltekEmulator extends AbstractEmulator implements Emulator {
 
+  long[] DELAY_TIMES = { 1, 2, 5, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000, 30000, 60000 };
+
   public HoltekEmulator(WebSessionModel model) {
     super(model);
   }
 
+  @Override
+  protected void doSetA(byte data) {
+    getModel().getWork().setRegisterA(data);
+  }
+
+  @Override
+  protected void doCalc(byte data) {
+    WorkingModel work = getModel().getWork();
+    switch (data) {
+    case 1:
+      work.setRegisterA((byte) (work.getRegisterA() + 1));
+      break;
+    case 2:
+      work.setRegisterA((byte) (work.getRegisterA() - 1));
+      break;
+    case 3:
+      work.setRegisterA((byte) (work.getRegisterA() + work.getRegisterB()));
+      break;
+    case 4:
+      work.setRegisterA((byte) (work.getRegisterA() - work.getRegisterB()));
+      break;
+    case 5:
+      work.setRegisterA((byte) (work.getRegisterA() * work.getRegisterB()));
+      break;
+    case 6:
+      work.setRegisterA((byte) (work.getRegisterA() / work.getRegisterB()));
+      break;
+    case 7:
+      work.setRegisterA((byte) (work.getRegisterA() & work.getRegisterB()));
+      break;
+    case 8:
+      work.setRegisterA((byte) (work.getRegisterA() | work.getRegisterB()));
+      break;
+    case 9:
+      work.setRegisterA((byte) (work.getRegisterA() ^ work.getRegisterB()));
+      break;
+    case 10:
+      work.setRegisterA((byte) (~work.getRegisterA()));
+      break;
+    default:
+      break;
+    }
+  }
+
+  @Override
+  protected void doCall(byte data) {
+    getModel().getWork().setRaddress(getModel().getWork().getAddress());
+    doJump(data);
+  }
+
+  @Override
+  protected void doNop(byte data) {
+    return;
+  }
+
+  @Override
+  protected void doPort(byte data) {
+    getModel().getOutput().setOutput1((data & 0x01) > 0);
+    getModel().getOutput().setOutput2((data & 0x02) > 0);
+    getModel().getOutput().setOutput3((data & 0x04) > 0);
+    getModel().getOutput().setOutput4((data & 0x08) > 0);
+  }
+
+  @Override
+  protected void doDelay(byte data) {
+    try {
+      Thread.sleep(DELAY_TIMES[data]);
+    } catch (InterruptedException e) {
+      e.printStackTrace();
+    }
+  }
+
+  @Override
+  protected void doJumpBack(byte data) {
+    short address = getModel().getWork().getAddress();
+    address -= data;
+    if (address < 0) {
+      address = 0;
+    }
+    getModel().getWork().setAddress((short) (address - 1));
+  }
+
+  @Override
+  protected void doAIs(byte data) {
+    WorkingModel work = getModel().getWork();
+    switch (data) {
+    case 1:
+      work.setRegisterA(work.getRegisterB());
+      break;
+    case 2:
+      work.setRegisterA(work.getRegisterC());
+      break;
+    case 3:
+      work.setRegisterA(work.getRegisterD());
+      break;
+    case 4:
+      byte value = (byte) (getModel().getInput().isInput1() ? 1 : 0);
+      value += (byte) (getModel().getInput().isInput2() ? 2 : 0);
+      value += (byte) (getModel().getInput().isInput3() ? 4 : 0);
+      value += (byte) (getModel().getInput().isInput4() ? 8 : 0);
+      work.setRegisterA(value);
+      break;
+    case 5:
+      work.setRegisterA((byte) (getModel().getInput().isInput1() ? 1 : 0));
+      break;
+    case 6:
+      work.setRegisterA((byte) (getModel().getInput().isInput2() ? 1 : 0));
+      break;
+    case 7:
+      work.setRegisterA((byte) (getModel().getInput().isInput3() ? 1 : 0));
+      break;
+    case 8:
+      work.setRegisterA((byte) (getModel().getInput().isInput4() ? 1 : 0));
+      break;
+    case 9:
+      work.setRegisterA((byte) (getModel().getInput().getAdc1()));
+      break;
+    case 10:
+      work.setRegisterA((byte) (getModel().getInput().getAdc2()));
+      break;
+    default:
+      break;
+    }
+  }
+
+  @Override
+  protected void doIsA(byte data) {
+    WorkingModel work = getModel().getWork();
+    switch (data) {
+    case 0:
+      byte temp = work.getRegisterA();
+      work.setRegisterA(work.getRegisterB());
+      work.setRegisterB(temp);
+      break;
+    case 1:
+      work.setRegisterB(work.getRegisterA());
+      break;
+    case 2:
+      work.setRegisterC(work.getRegisterA());
+      break;
+    case 3:
+      work.setRegisterD(work.getRegisterA());
+      break;
+    case 4:
+      doPort(work.getRegisterA());
+      break;
+    case 5:
+      getModel().getOutput().setOutput1((work.getRegisterA() & 0x01) > 0);
+      break;
+    case 6:
+      getModel().getOutput().setOutput2((work.getRegisterA() & 0x02) > 0);
+      break;
+    case 7:
+      getModel().getOutput().setOutput3((work.getRegisterA() & 0x04) > 0);
+      break;
+    case 8:
+      getModel().getOutput().setOutput4((work.getRegisterA() & 0x08) > 0);
+      break;
+    case 9:
+      getModel().getOutput().setPwm1((byte) ((work.getRegisterA() & 0x0F) << 4));
+      break;
+    case 10:
+      getModel().getOutput().setPwm2((byte) ((work.getRegisterA() & 0x0F) << 4));
+      break;
+    default:
+      break;
+    }
+  }
+
+  @Override
+  protected void doPage(byte data) {
+    byte value = (byte) (data & 0x07);
+    getModel().getWork().setPage(value);
+  }
+
+  @Override
+  protected void doJump(byte data) {
+    int value = data + (16 * getModel().getWork().getPage());
+    getModel().getWork().setAddress((short) (value - 1));
+  }
+
+  @Override
+  protected void doCCount(byte data) {
+    byte value = getModel().getWork().getRegisterC();
+    if (value > 0) {
+      value -= 1;
+      getModel().getWork().setRegisterC(value);
+      doJump(data);
+    }
+  }
+
+  @Override
+  protected void doDCount(byte data) {
+    byte value = getModel().getWork().getRegisterD();
+    if (value > 0) {
+      value -= 1;
+      getModel().getWork().setRegisterD(value);
+      doJump(data);
+    }
+  }
+
+  @Override
+  protected void doSkip(byte data) {
+    WorkingModel work = getModel().getWork();
+    boolean skip = false;
+    switch (data) {
+    case 1:
+      skip = (work.getRegisterA() > work.getRegisterB());
+      break;
+    case 2:
+      skip = (work.getRegisterA() < work.getRegisterB());
+      break;
+    case 3:
+      skip = (work.getRegisterA() == work.getRegisterB());
+      break;
+    case 4:
+      skip = getModel().getInput().isInput1();
+      break;
+    case 5:
+      skip = getModel().getInput().isInput2();
+      break;
+    case 6:
+      skip = getModel().getInput().isInput3();
+      break;
+    case 7:
+      skip = getModel().getInput().isInput4();
+      break;
+    case 8:
+      skip = !getModel().getInput().isInput1();
+      break;
+    case 9:
+      skip = !getModel().getInput().isInput2();
+      break;
+    case 10:
+      skip = !getModel().getInput().isInput3();
+      break;
+    case 11:
+      skip = !getModel().getInput().isInput4();
+      break;
+    case 12:
+      skip = !getModel().getInput().isPrg();
+      break;
+    case 13:
+      skip = !getModel().getInput().isSel();
+      break;
+    case 14:
+      skip = getModel().getInput().isPrg();
+      break;
+    case 15:
+      skip = getModel().getInput().isSel();
+      break;
+    default:
+      break;
+    }
+    if (skip) {
+      int value = getModel().getWork().getAddress();
+      getModel().getWork().setAddress((short) (value + 1));
+    }
+  }
+
+  @Override
+  protected void doCallSub(byte data) {
+    if (data == 0) {
+      getModel().getWork().setAddress(getModel().getWork().getRaddress());
+    }
+  }
+
+  @Override
+  protected void doByte(byte data) {
+
+  }
+
 }

+ 1 - 0
src/main/java/de/mcs/tools/sps/emulator/model/CommandModel.java

@@ -43,6 +43,7 @@ public class CommandModel {
       getAvailableCommands().add(COMMAND.STOP);
       getAvailableCommands().add(COMMAND.RESET);
       break;
+    case COMPILE:
     case RESET:
     case NN:
       getAvailableCommands().add(COMMAND.START);

+ 17 - 0
src/main/java/de/mcs/tools/sps/emulator/model/ProgramModel.java

@@ -15,6 +15,7 @@ public class ProgramModel {
   private byte[] bin;
   private boolean modified;
   private int actualLine;
+  private int[] bin2SrcLine;
 
   public ProgramModel() {
     hardware = Hardware.HOLTEK;
@@ -138,4 +139,20 @@ public class ProgramModel {
     }
     return isModified();
   }
+
+  /**
+   * @return the bin2SrcLine
+   */
+  public int[] getBin2SrcLine() {
+    return bin2SrcLine;
+  }
+
+  /**
+   * @param bin2SrcLine
+   *          the bin2SrcLine to set
+   */
+  public void setBin2SrcLine(int[] bin2SrcLine) {
+    this.bin2SrcLine = bin2SrcLine;
+  }
+
 }

+ 22 - 4
src/main/java/de/mcs/tools/sps/emulator/model/WebSessionModel.java

@@ -33,6 +33,7 @@ public class WebSessionModel {
   private OutputModel output;
   private WorkingModel work;
   private String message;
+  private String stacktrace;
   private boolean error;
 
   public WebSessionModel() {
@@ -46,8 +47,9 @@ public class WebSessionModel {
   @Override
   public String toString() {
     StringBuilder b = new StringBuilder();
-    b.append(String.format("%s:[program: %s, command: %s, input: %s, output: %s, work: %s]",
-        this.getClass().getSimpleName(), program, command, input, output, work));
+    b.append(String.format(
+        "%s:[error: %s, message: %s, stacktrace, %s, program: %s, command: %s, input: %s, output: %s, work: %s]",
+        this.getClass().getSimpleName(), error, message, getStacktrace(), program, command, input, output, work));
     return b.toString();
   }
 
@@ -134,7 +136,8 @@ public class WebSessionModel {
   }
 
   /**
-   * @param message the message to set
+   * @param message
+   *          the message to set
    */
   public void setMessage(String message) {
     this.message = message;
@@ -148,9 +151,24 @@ public class WebSessionModel {
   }
 
   /**
-   * @param error the error to set
+   * @param error
+   *          the error to set
    */
   public void setError(boolean error) {
     this.error = error;
   }
+
+  /**
+   * @return the stacktrace
+   */
+  public String getStacktrace() {
+    return stacktrace;
+  }
+
+  /**
+   * @param stacktrace the stacktrace to set
+   */
+  public void setStacktrace(String stacktrace) {
+    this.stacktrace = stacktrace;
+  }
 }

+ 2 - 17
src/main/java/de/mcs/tools/sps/emulator/model/WorkingModel.java

@@ -21,7 +21,6 @@ public class WorkingModel {
   private short address;
 
   private List<Integer> stack = new ArrayList<>();
-  private int[] bin2SrcLine;
   private WORKINGSTATE workingstate;
 
   @Override
@@ -184,21 +183,6 @@ public class WorkingModel {
     this.stack = stack;
   }
 
-  /**
-   * @return the bin2SrcLine
-   */
-  public int[] getBin2SrcLine() {
-    return bin2SrcLine;
-  }
-
-  /**
-   * @param bin2SrcLine
-   *          the bin2SrcLine to set
-   */
-  public void setBin2SrcLine(int[] bin2SrcLine) {
-    this.bin2SrcLine = bin2SrcLine;
-  }
-
   /**
    * @return the workingstate
    */
@@ -207,7 +191,8 @@ public class WorkingModel {
   }
 
   /**
-   * @param workingstate the workingstate to set
+   * @param workingstate
+   *          the workingstate to set
    */
   public void setWorkingstate(WORKINGSTATE workingstate) {
     this.workingstate = workingstate;

+ 46 - 17
src/main/java/de/mcs/tools/sps/emulator/resources/EmulatorResource.java

@@ -1,10 +1,15 @@
 package de.mcs.tools.sps.emulator.resources;
 
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
 import javax.ws.rs.GET;
 import javax.ws.rs.POST;
 import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
 import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response.Status;
 
 import de.mcs.tools.sps.emulator.Emulator;
 import de.mcs.tools.sps.emulator.EmulatorFactory;
@@ -26,23 +31,36 @@ public class EmulatorResource {
     model = checkModel(model);
     Emulator emulator = EmulatorFactory.getEmulator(model);
     COMMAND actualCommand = model.getCommand().getActualCommand();
-    switch (actualCommand) {
-    case NN:
-      break;
-    case START:
-      emulator.start();
-      break;
-    case NEXT:
-      emulator.next();
-      break;
-    case STOP:
-      emulator.stop();
-      break;
-    case COMPILE:
-      emulator.compile();
-      break;
-    default:
-      break;
+    try {
+      switch (actualCommand) {
+      case NN:
+        break;
+      case START:
+        emulator.start();
+        break;
+      case NEXT:
+        emulator.next();
+        break;
+      case STOP:
+        emulator.stop();
+        break;
+      case COMPILE:
+        emulator.compile();
+        break;
+      default:
+        break;
+      }
+    } catch (Exception e) {
+      String stackTrace = (e != null) ? "\n" + getStacktraceAsString(e) : "";
+      String errorMessage = String.format("%s%s", e.getClass().getName(),
+          e.getMessage() == null ? "" : ":" + e.getMessage());
+      model.setMessage(errorMessage);
+      model.setStacktrace(stackTrace);
+      model.setError(true);
+      e.printStackTrace();
+    }
+    if (model.isError()) {
+      throw new WebApplicationException(model.getMessage(), Status.BAD_REQUEST);
     }
     return model;
   }
@@ -57,4 +75,15 @@ public class EmulatorResource {
     }
     return model;
   }
+
+  private String getStacktraceAsString(Throwable e) {
+    String stackTrace = "";
+    if (e != null) {
+      StringWriter writer = new StringWriter();
+      e.printStackTrace(new PrintWriter(writer));
+      stackTrace += writer.toString();
+    }
+    return stackTrace;
+  }
+
 }

+ 103 - 0
src/main/java/de/mcs/utils/BaseApiModel.java

@@ -0,0 +1,103 @@
+package de.mcs.utils;
+/**
+ * 
+ */
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.fasterxml.jackson.annotation.JsonAnyGetter;
+import com.fasterxml.jackson.annotation.JsonAnySetter;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+
+/**
+ * @author w.klaas
+ */
+public class BaseApiModel {
+
+  private Map<String, Object> values;
+
+  /**
+   * 
+   */
+  public BaseApiModel() {
+    values = new HashMap<>();
+  }
+
+  /**
+   * @param name
+   *          name of the field
+   * @param value
+   *          value of the field
+   */
+  @JsonAnySetter
+  public void setKeyValue(String name, Object value) {
+    values.put(name, value);
+  }
+
+  /**
+   * simple setting fuild values
+   * 
+   * @param name
+   *          name of the field
+   * @param value
+   *          value of the field
+   * @return BaseApiModel
+   */
+  @JsonIgnore
+  public BaseApiModel set(String name, Object value) {
+    values.put(name, value);
+    return this;
+  }
+
+  /**
+   * @return a map with all fields
+   */
+  @JsonAnyGetter
+  public Map<String, Object> getAny() {
+    return values;
+  }
+
+  /**
+   * getting the value of a single field with the desired name
+   * 
+   * @param name
+   *          the name of the field to get
+   * @return value the value of the field, or <code>null</code>
+   */
+  public Object getField(String name) {
+    return values.get(name);
+  }
+
+  /**
+   * getting the value of a single field with the desired name
+   * 
+   * @param name
+   *          the name of the field to get
+   * @return value the value of the field as a string, or <code>null</code>
+   */
+  public String getFieldValueAsString(String name) {
+    Object fieldValue = getField(name);
+    if (fieldValue != null) {
+      return fieldValue.toString();
+    }
+    return null;
+  }
+
+  @Override
+  public String toString() {
+    return values.toString();
+  }
+
+  /**
+   * testing if an field is availble
+   * 
+   * @param name
+   *          name of the field
+   * @return <code>true</code> if the field is present
+   */
+  public boolean hasField(String name) {
+    return values.containsKey(name);
+  }
+
+}

+ 93 - 0
src/main/java/de/mcs/utils/Kryption.java

@@ -0,0 +1,93 @@
+package de.mcs.utils;
+/**
+ * 
+ */
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.security.GeneralSecurityException;
+import java.util.Base64;
+
+import javax.crypto.Cipher;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.PBEParameterSpec;
+
+/**
+ * @author wklaa_000
+ */
+public class Kryption {
+
+  /**
+   * main method for external encryption of passwords. Needed for the setup.
+   * 
+   * @param args
+   *          index 0 will be the password to encrypt
+   */
+  public static void main(String[] args) {
+    if (args.length > 0) {
+      try {
+        System.out.println(Kryption.encrypt(args[0]));
+        System.exit(0);
+      } catch (UnsupportedEncodingException | GeneralSecurityException e) {
+        e.printStackTrace();
+        System.exit(-1);
+      }
+    }
+    System.exit(-1);
+  }
+
+  private static final char[] PASSWORD = "fgagwetizxmapoywnoouh".toCharArray();
+  private static final byte[] SALT = { (byte) 0xde, (byte) 0x33, (byte) 0x10, (byte) 0x12, (byte) 0xde, (byte) 0x33,
+      (byte) 0x10, (byte) 0x12, };
+
+  /**
+   * encrypt this string.
+   * 
+   * @param string
+   *          the string to encrypt
+   * @return the encrypted and mime coded string.
+   * @throws GeneralSecurityException
+   *           if something goes wrong.
+   * @throws UnsupportedEncodingException
+   *           if something goes wrong.
+   */
+  public static String encrypt(String string) throws GeneralSecurityException, UnsupportedEncodingException {
+    SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
+    SecretKey key = keyFactory.generateSecret(new PBEKeySpec(PASSWORD));
+    Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
+    pbeCipher.init(Cipher.ENCRYPT_MODE, key, new PBEParameterSpec(SALT, 20));
+    return base64Encode(pbeCipher.doFinal(string.getBytes("UTF-8")));
+  }
+
+  private static String base64Encode(byte[] bytes) {
+    // NB: This class is internal, and you probably should use another impl
+    return Base64.getEncoder().encodeToString(bytes);
+  }
+
+  /**
+   * decrypt this string.
+   * 
+   * @param string
+   *          the string to decrypt
+   * @return the mime decoded and decrypted string.
+   * @throws GeneralSecurityException
+   *           if something goes wrong.
+   * @throws IOException
+   *           if something goes wrong.
+   */
+  public static String decrypt(String string) throws GeneralSecurityException, IOException {
+    SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
+    SecretKey key = keyFactory.generateSecret(new PBEKeySpec(PASSWORD));
+    Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
+    pbeCipher.init(Cipher.DECRYPT_MODE, key, new PBEParameterSpec(SALT, 20));
+    return new String(pbeCipher.doFinal(base64Decode(string)), "UTF-8");
+  }
+
+  private static byte[] base64Decode(String property) throws IOException {
+    // NB: This class is internal, and you probably should use another impl
+    return Base64.getDecoder().decode(property);
+  }
+
+}

+ 40 - 0
src/main/java/de/mcs/utils/Logger.java

@@ -0,0 +1,40 @@
+/**
+ * 
+ */
+package de.mcs.utils;
+
+/**
+ * @author w.klaas
+ */
+public class Logger {
+
+  public static Logger getLogger(Class<?> class1) {
+    return new Logger(class1);
+  }
+
+  private org.apache.log4j.Logger logger;
+
+  public Logger(Class<?> class1) {
+    logger = org.apache.log4j.Logger.getLogger(class1);
+  }
+
+  public void debug(String string, Object... args) {
+    logger.debug(String.format(string, args));
+  }
+
+  public void info(String string, Object... args) {
+    logger.info(String.format(string, args));
+  }
+
+  public void error(String string, Object... args) {
+    logger.error(String.format(string, args));
+  }
+
+  public void error(Throwable t, String string, Object... args) {
+    logger.error(String.format(string, args), t);
+  }
+
+  public void error(Throwable t) {
+    logger.error(t);
+  }
+}

+ 69 - 0
src/main/java/de/mcs/utils/Macro.java

@@ -0,0 +1,69 @@
+package de.mcs.utils;
+/**
+ * 
+ */
+
+/**
+ * @author w.klaas
+ */
+public class Macro {
+
+  private String value;
+  private String name;
+
+  /**
+   * Constructs a new macro
+   * 
+   * @param macroName
+   *          name of the macro
+   * @param value
+   *          value for substitution
+   */
+  public Macro(String macroName, String value) {
+    this.name = macroName;
+    this.value = value;
+  }
+
+  /**
+   * @return the value for substitution
+   */
+  public String getValue() {
+    return value;
+  }
+
+  /**
+   * @param value
+   *          setting a new value for this macro
+   */
+  public void setValue(String value) {
+    this.value = value;
+  }
+
+  /**
+   * @return name of this macro.
+   */
+  public String getMacroName() {
+    return name;
+  }
+
+  /**
+   * @return same as getMacroName(), but with the {} delimiter.
+   */
+  public String getMacroDefinition() {
+    StringBuilder b = new StringBuilder();
+    b.append('{');
+    b.append(getMacroName());
+    b.append('}');
+    return b.toString();
+  }
+
+  /*
+   * (non-Javadoc)
+   * @see java.lang.Object#toString()
+   */
+  @Override
+  public String toString() {
+    return String.format("%s=\"%s\"", getMacroDefinition(), getValue());
+  }
+
+}

+ 119 - 0
src/main/java/de/mcs/utils/Macros.java

@@ -0,0 +1,119 @@
+package de.mcs.utils;
+/**
+ * 
+ */
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * This implements a iterable list of unique {@link Macro}.
+ * 
+ * @author w.klaas
+ */
+public class Macros implements Iterable<Macro> {
+
+  private List<Macro> macroTable;
+
+  /**
+   * Default constructor for the macro list
+   */
+  public Macros() {
+    this.macroTable = new ArrayList<>();
+  }
+
+  /**
+   * adding a new macro definition to this list. If the name is already present, only the value will be changed.
+   * 
+   * @param name
+   *          name of the new macro
+   * @param value
+   *          substitution value of the macro
+   */
+  public void addMacro(String name, String value) {
+    for (Iterator<Macro> iterator = macroTable.iterator(); iterator.hasNext();) {
+      Macro macro = (Macro) iterator.next();
+      if (macro.getMacroName().equals(name)) {
+        macro.setValue(value);
+        return;
+      }
+    }
+    macroTable.add(new Macro(name, value));
+  }
+
+  /**
+   * adding a new macro definition to this list. If the name is already present, only the value will be changed.
+   * 
+   * @param macro
+   *          the macro to be added
+   */
+  public void addMacro(Macro macro) {
+    for (Iterator<Macro> iterator = macroTable.iterator(); iterator.hasNext();) {
+      Macro myMacro = (Macro) iterator.next();
+      if (myMacro.getMacroName().equals(macro.getMacroName())) {
+        myMacro.setValue(macro.getValue());
+        return;
+      }
+    }
+    macroTable.add(macro);
+  }
+
+  /**
+   * @return iterator over this list of macros
+   */
+  public Iterator<Macro> iterator() {
+    return macroTable.iterator();
+  }
+
+  /**
+   * substitue a string with macros. All Macros should be name in the string as {macroname}.
+   * 
+   * @param text
+   *          the original string with the macro definitions in
+   * @return the substituted string
+   */
+  public String substitute(final String text) {
+    StringBuilder stringBuilder = new StringBuilder(text);
+    for (Macro macro : this) {
+      int index = stringBuilder.indexOf(macro.getMacroDefinition());
+      if (index != -1) {
+        stringBuilder.replace(index, index + macro.getMacroDefinition().length(), macro.getValue());
+      }
+    }
+    return stringBuilder.toString();
+  }
+
+  /**
+   * getting a single macro from the list of macros
+   * 
+   * @param name
+   *          the name of the macros to get
+   * @return the desired macro or <code>null</code> if the macro is not present.
+   */
+  public Macro getMacro(String name) {
+    for (Iterator<Macro> iterator = macroTable.iterator(); iterator.hasNext();) {
+      Macro macro = (Macro) iterator.next();
+      if (macro.getMacroName().equals(name)) {
+        return macro;
+      }
+    }
+    return null;
+  }
+
+  /*
+   * (non-Javadoc)
+   * @see java.lang.Object#toString()
+   */
+  @Override
+  public String toString() {
+    StringBuilder b = new StringBuilder();
+    for (Iterator<Macro> iterator = macroTable.iterator(); iterator.hasNext();) {
+      Macro macro = (Macro) iterator.next();
+      b.append(macro.toString());
+      b.append(',');
+    }
+    return String.format("[%s]", b.substring(0, b.length() - 1));
+  }
+
+}

+ 86 - 0
src/main/java/de/mcs/utils/SignUtils.java

@@ -0,0 +1,86 @@
+package de.mcs.utils;
+
+import static org.junit.Assert.fail;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyStore;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.Base64;
+
+public class SignUtils {
+
+  private static final String KEYSTORE_PASSWORD = "easy1234";
+
+  /**
+   * signing a string with the private key from the keystore. (should be in the working directory, named keystore.jks)
+   * 
+   * @param string
+   * @return the signature as a mimecoded string
+   * @throws GeneralSecurityException
+   * @throws FileNotFoundException
+   * @throws IOException
+   */
+  public static String signString(String string) throws GeneralSecurityException, FileNotFoundException, IOException {
+    byte[] data = string.getBytes("UTF8");
+
+    KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
+    keyStore.load(new FileInputStream("keystore.jks"), KEYSTORE_PASSWORD.toCharArray());
+
+    Key key = keyStore.getKey("selfsigned", KEYSTORE_PASSWORD.toCharArray());
+    if (!(key instanceof PrivateKey)) {
+      fail("key is not a private key");
+    }
+    // Certificate keystoreCertificate = keyStore.getCertificate("selfsigned");
+
+    Signature sig = Signature.getInstance("SHA512withRSA");
+    sig.initSign((PrivateKey) key);
+    sig.update(data);
+    byte[] signatureBytes = sig.sign();
+    String mimeCodedSignature = Base64.getEncoder().encodeToString(signatureBytes);
+    // System.out.println("Singature:" + mimeCodedSignature);
+    return mimeCodedSignature;
+  }
+
+  /**
+   * verifies the signature of a string. The public key is stored in the local file system as X509 certificate name
+   * x509.cer
+   * 
+   * @param string
+   *          the source string
+   * @param signature
+   *          the signature to check
+   * @return <code>true</code> if the signature is correct otherwise <code>false</code>
+   * @throws UnsupportedEncodingException
+   * @throws NoSuchAlgorithmException
+   * @throws FileNotFoundException
+   * @throws CertificateException
+   * @throws InvalidKeyException
+   * @throws SignatureException
+   */
+  public static boolean verifySignature(String string, String signature) throws UnsupportedEncodingException,
+      NoSuchAlgorithmException, FileNotFoundException, CertificateException, InvalidKeyException, SignatureException {
+    byte[] signatureBytes = Base64.getDecoder().decode(signature);
+    byte[] data = string.getBytes("UTF8");
+    Signature sig = Signature.getInstance("SHA512withRSA");
+
+    FileInputStream fileinputstream = new FileInputStream("x509.cer");
+    // Generate a certificate from the data in the file.
+    CertificateFactory certificatefactory = CertificateFactory.getInstance("X.509");
+    X509Certificate x509certificate = (X509Certificate) certificatefactory.generateCertificate(fileinputstream);
+    sig.initVerify(x509certificate.getPublicKey());
+    sig.update(data);
+    return sig.verify(signatureBytes);
+  }
+}

+ 13 - 0
src/main/java/de/mcs/utils/Singleton.java

@@ -0,0 +1,13 @@
+package de.mcs.utils;
+
+public class Singleton {
+
+  private static Singleton instance = new Singleton();
+
+  private Singleton() {
+  }
+
+  public static Singleton getInstance() {
+    return instance;
+  }
+}

+ 3 - 0
src/main/resources/banner.txt

@@ -0,0 +1,3 @@
+#Implementation-Title
+ 
+#Implementation-Title by #Implementation-Vendor  Version: #Implementation-Version

+ 39 - 0
src/main/resources/log4j.xml

@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
+	<appender name="fileAppender" class="org.apache.log4j.DailyRollingFileAppender">
+		<param name="datePattern" value="'.'yyyy-MM-dd_HH-mm" />
+		<param name="file" value="log/logging.log" />
+		<param name="Append" value="true" />
+		<layout class="org.apache.log4j.PatternLayout">
+			<param name="ConversionPattern" value="%d{ISO8601} %-5p [%t] %c: %m%n" />
+		</layout>
+	</appender>
+
+	<appender name="console" class="org.apache.log4j.ConsoleAppender">
+		<param name="Target" value="System.out" />
+		<layout class="org.apache.log4j.PatternLayout">
+			<param name="ConversionPattern" value="%r [%t] %-5p %C{1}#%M: %m%n" />
+		</layout>
+	</appender>
+
+	<logger name="org">
+		<level value="warn" />
+	</logger>
+	
+	<logger name="com">
+		<level value="warn" />
+	</logger>
+
+	<logger name="de">
+		<level value="debug" />
+	</logger>
+	
+	<root>
+		<priority value="info" />
+		<appender-ref ref="fileAppender" />
+		<appender-ref ref="console" />
+	</root>
+
+</log4j:configuration>

+ 21 - 0
src/main/resources/logback.xml

@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+
+	<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+		<layout class="ch.qos.logback.classic.PatternLayout">
+			<Pattern>
+				%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n
+			</Pattern>
+		</layout>
+	</appender>
+
+	<logger name="com.mkyong.web" level="debug"
+		additivity="false">
+		<appender-ref ref="STDOUT" />
+	</logger>
+
+	<root level="error">
+		<appender-ref ref="STDOUT" />
+	</root>
+
+</configuration>