Browse Source

migration from github

lucaconte 4 years ago
parent
commit
2e1bb2dd45

+ 43 - 0
build.gradle

@@ -0,0 +1,43 @@
+apply plugin: 'java'
+apply plugin: 'groovy'
+apply plugin: 'application'
+apply plugin: 'eclipse'
+apply plugin: 'idea'
+
+
+
+version = '1.2.' + (System.getenv('BUILD_NUMBER') ?: 0)
+sourceCompatibility = 1.7
+targetCompatibility = 1.7
+mainClassName = "org.django.acquabooks.CommandLineLauncher"
+//mainClassName = "org.django.acquabooks.io.Console"
+
+
+//Get dependencies from Maven central repository
+repositories {
+    mavenCentral()
+    maven {
+        url "https://oss.sonatype.org/content/groups/public/"
+    }
+
+}
+
+//Project dependencies
+dependencies {
+  compile 'ch.qos.logback:logback-classic:1.1.3'
+  compile 'commons-cli:commons-cli:1.3.1'
+  compile 'io.searchbox:jest:0.1.6'
+  compile 'org.apache.commons:commons-lang3:3.4'
+  compile 'org.apache.poi:poi:3.12'
+  compile 'commons-beanutils:commons-beanutils:1.9.2'
+  //dipendenza utile qualora si voleese dare veste grafia a tutto stle ncurses
+  //compile 'com.baulsupp.kolja:jcurses:0.9.5.3'
+}
+
+jar {
+    dependsOn configurations.runtime
+    from { configurations.runtime.collect { it.isDirectory() ? it : zipTree(it).matching{ exclude{it.path.contains('META-INF')}}} } 
+    manifest {
+        attributes 'Main-Class': mainClassName
+    }
+}

+ 184 - 0
src/main/java/org/django/acquabooks/CommandLineLauncher.java

@@ -0,0 +1,184 @@
+package org.django.acquabooks;
+
+import org.apache.commons.cli.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class CommandLineLauncher {
+  
+  private static final Logger logger = LoggerFactory.getLogger(CommandLineLauncher.class);
+  
+  private Options options;
+  private Parser parser;
+ 
+  
+ public static void main(String[] args) {
+   CommandLineLauncher cl=new CommandLineLauncher();
+   if(args.length==0){
+             HelpFormatter formatter = new HelpFormatter();
+             formatter.printHelp( "java -jar acquabooks<VERSION>.jar -H <HOST> <command> ", CommandLineLauncher.getOptionsInstance() );
+             System.exit(1);
+   }
+    
+
+   String host = "localhost";
+    String port = "9200"; 
+  
+   try {
+     CommandLine line = cl.getParser().parse( cl.getOptions(), args );
+
+     if(line.hasOption("h")){
+       HelpFormatter formatter = new HelpFormatter();
+       formatter.printHelp( "java -jar acquabooks<VERSION>.jar -H <HOST> <command> ", cl.getOptions() );
+       System.exit(0);
+     }
+     
+     if(line.hasOption("H")){
+       host = line.getOptionValue("H");
+     }
+     
+     if(line.hasOption("P")){
+       port = line.getOptionValue("P");
+     }
+   
+    
+     //modalità di funzionamento esclusive
+     if(line.hasOption("s")){
+      
+        SellingManager m = new SellingManager(ElasticRESTClient.getInstance("http", host, port)); 
+        m.run();
+     }else if(line.hasOption("d")){
+      
+        SellingManager m = new SellingManager(ElasticRESTClient.getInstance("http", host, port)); 
+        m.runDetail();
+     }else if(line.hasOption("i")){
+        ImportManager m = new ImportManager(line.getOptionValue("i"),ElasticRESTClient.getInstance("http", host, port)); 
+        m.run();
+     }else if(line.hasOption("u")){
+        ImportManager m = new ImportManager(line.getOptionValue("u"), ImportManager.MODE_EDIT, ElasticRESTClient.getInstance("http", host, port));
+        m.run();
+     }else if(line.hasOption("z")){
+        ImportManager m = new ImportManager(line.getOptionValue("z"), ImportManager.MODE_AZZERA_VENDUTO, ElasticRESTClient.getInstance("http", host, port));
+        m.run();
+     }else if(line.hasOption("x")){
+        ExtractionManager m = new ExtractionManager(ElasticRESTClient.getInstance("http", host, port), line.getOptionValue("x"));
+        m.run();
+     }else if(line.hasOption("cr")){
+        CrudManager m = new CrudManager(ElasticRESTClient.getInstance("http", host, port));
+        m.insert();
+     }else if(line.hasOption("up")){
+        CrudManager m = new CrudManager(ElasticRESTClient.getInstance("http", host, port));
+        m.update();
+     }else if(line.hasOption("del")){
+        CrudManager m = new CrudManager(ElasticRESTClient.getInstance("http", host, port));
+        m.delete();
+     }
+   } catch (ParseException e1) {
+      System.out.println(e1.getMessage());
+   
+   }
+
+ }
+
+
+ public static Options getOptionsInstance(){
+    DefaultParser parser = new DefaultParser();
+    // create the Options
+
+    Options options = new Options();
+    options.addOption( "h", "help", false, "Print this comman line help" );
+    
+    options.addOption(Option.builder( "H" )
+        .desc( "ElasticSearch host")
+        .required(false)
+        .hasArg()
+        .argName("HOST")
+        .longOpt("hostname").build());
+
+    options.addOption( Option.builder( "p" )
+        .desc( "ElasticSearch port [default 9200]")
+        .required(false)
+        .hasArg()
+        .argName("PORT")
+        .longOpt("port").build() );
+ 
+    OptionGroup optionGroup = new OptionGroup();
+     optionGroup.addOption( Option.builder( "x" )
+        .desc( "Export: it extract data ad save to a single file in the current directory" +
+                " the argument accept the type of export. L\'ultima opzione è excel|json e determina il formato di output\n" +
+                " \"-x T,json\" exports ALL data in json format\n" +
+                " \"-x E,pippo,excel\" esporta libri che metchano la parola pippo in tags o editore")
+        .required(false)
+        .hasArg()
+        .argName("TYPE_OF_EXPORT")
+        .longOpt("extract").build() );
+
+
+
+     optionGroup.addOption( Option.builder("s")
+        .desc("Selling mode")
+        .required(false)
+        .build());
+    
+    optionGroup.addOption( Option.builder("d")
+        .desc("Detail mode")
+        .required(false)
+        .build());
+     optionGroup.addOption( Option.builder("cr")
+        .desc("Create new")
+        .required(false)
+        .build());
+     optionGroup.addOption( Option.builder( "up" )
+        .desc( "Update a book")
+        .required(false)
+        .build());
+     optionGroup.addOption( Option.builder( "del" )
+        .desc( "Delete book")
+        .required(false)
+        .build());
+
+
+
+    optionGroup.addOption( Option.builder( "i" )
+        .desc( "file to import")
+        .required(false)
+        .hasArg()
+        .argName("FILE")
+        .longOpt("import").build() );
+    
+    optionGroup.addOption( Option.builder( "u" )
+        .desc( "file to import in update/edit mode: as 'import' but differently to it, if the record already exist it will be updated and not skipped")
+        .required(false)
+        .hasArg()
+        .argName("FILE")
+        .longOpt("update").build() );
+
+   optionGroup.addOption( Option.builder( "z" )
+        .desc("update QA subtracting QV and reset QV.  A json file qith libro is accepted. The only barcod property is considered")
+        .required(false)
+        .hasArg()
+        .argName("FILE")
+        .longOpt("reset").build() );
+
+    options.addOptionGroup(optionGroup); 
+    return  options;
+  }
+
+  public Options getOptions() {
+    if (options == null) {
+      options =  getOptionsInstance();
+    }
+
+    return options;
+  }
+
+  public Parser getParser() {
+    if (parser == null) {
+      parser =   new PosixParser();
+      
+    }
+
+    return parser;
+  }
+
+}

+ 214 - 0
src/main/java/org/django/acquabooks/CrudManager.java

@@ -0,0 +1,214 @@
+package org.django.acquabooks;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+
+import org.apache.commons.lang3.StringUtils;
+import org.django.acquabooks.pojos.Libro;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class CrudManager {
+  public static String STOP_READING_SEQUENCE = "q";
+  public static int CONSOLE_ROW_LENGHT = 80;
+
+  private static final Logger logger = LoggerFactory
+                        .getLogger(CommandLineLauncher.class);
+
+  private ElasticRESTClient elclient;
+
+  public CrudManager() {
+          elclient = ElasticRESTClient.getInstance("http", "localhost", "9200");
+  }
+
+  public CrudManager(ElasticRESTClient client){
+    elclient = client;
+  }
+  public boolean delete(){
+        String in = null;
+        InputStreamReader isr= null;
+        BufferedReader inp = null;
+
+
+        try {
+            isr =  new InputStreamReader(System.in);
+            inp = new BufferedReader(isr);
+
+            logWarn("CANCELLAZIONE LIBRO");
+            Libro l = new Libro();
+            System.out.println("Codice a barre: ");
+            l.setBarcode(inp.readLine());
+
+             return  elclient.delete(l.getBarcode());
+
+        }catch(Exception ex){
+            logErr(ex.getMessage());
+        }finally{
+            if(inp!=null){
+                try {
+                    inp.close();
+                }catch(Exception e){}
+            }
+            if(isr!=null){
+                try {
+                    isr.close();
+                }catch(Exception e){}
+            }
+        }
+        return false;
+    }
+
+  public int insert(){
+    String in = null;
+      InputStreamReader isr= null;
+    BufferedReader inp = null;
+
+
+      try {
+          isr =  new InputStreamReader(System.in);
+          inp = new BufferedReader(isr);
+
+          logWarn("INSERIMENTO NUOVO LIBRO");
+          Libro l = new Libro();
+          System.out.println("Codice a barre: ");
+          l.setBarcode(inp.readLine());
+          Libro lin = elclient.getDetail(l.getBarcode());
+          if(lin!=null){
+              logWarn("Libro già presente usa la funzionalità di edit per modificarne i contenuti");
+              return 1;
+          }
+
+
+          System.out.println("Editore: ");
+          l.setEditore(inp.readLine());
+
+          System.out.println("Autore: ");
+          l.setAutore(inp.readLine());
+
+          System.out.println("Titolo: ");
+          l.setTitolo(inp.readLine());
+
+          System.out.println("Prezzo [Es 14.00] : ");
+          l.setPrezzo(Double.parseDouble(inp.readLine()));
+
+          System.out.println("Percentuale notra [Es 0.25]: ");
+          l.setPercentuale(Double.parseDouble(inp.readLine()));
+
+          System.out.println("QA: ");
+          l.setQa(Integer.parseInt(inp.readLine()));
+
+          System.out.println("QV: ");
+          l.setQv(Integer.parseInt(inp.readLine()));
+
+          System.out.println("Tags [separati da virgola]: ");
+          l.setTag(inp.readLine());
+
+
+          //qui occorrerebbe validare
+           elclient.index(l);
+
+      }catch(Exception ex){
+          logErr(ex.getMessage());
+      }finally{
+        if(inp!=null){
+            try {
+                inp.close();
+            }catch(Exception e){}
+        }
+        if(isr!=null){
+            try {
+                isr.close();
+            }catch(Exception e){}
+        }
+      }
+    return 0;
+  }
+
+    public int update(){
+    String in = null;
+      InputStreamReader isr= null;
+    BufferedReader inp = null;
+
+
+      try {
+          isr =  new InputStreamReader(System.in);
+          inp = new BufferedReader(isr);
+
+          logWarn("MODIFICA LIBRO (tra parentesi graffe l'attuale valore del campo)");
+          System.out.println("Codice a barre: ");
+          Libro l = elclient.getDetail(inp.readLine());
+          if(l==null){
+              logWarn("Non eiste alcun libro con il codice a barre inserito");
+              return 1;
+          }
+
+          String sTmp = null;
+          System.out.println("Editore {" + l.getEditore() + "}: ");
+          sTmp = inp.readLine();
+          l.setEditore(!StringUtils.isEmpty(sTmp)?sTmp:l.getEditore());
+
+          System.out.println("Autore {" + l.getAutore() + "}: ");
+          sTmp = inp.readLine();
+          l.setAutore(!StringUtils.isEmpty(sTmp)?sTmp:l.getAutore());
+
+          System.out.println("Titolo {" + l.getTitolo() + "}: ");
+          sTmp = inp.readLine();
+          l.setTitolo(!StringUtils.isEmpty(sTmp)?sTmp:l.getTitolo());
+
+
+          System.out.println("Prezzo [Es 14.00]  {" + l.getPrezzo() + "}: ");
+          sTmp = inp.readLine();
+          l.setPrezzo(!StringUtils.isEmpty(sTmp)?Double.parseDouble(sTmp):l.getPrezzo());
+
+          System.out.println("Percentuale notra [Es 0.25] {" + l.getPercentuale() + "}: ");
+          sTmp = inp.readLine();
+          l.setPercentuale(!StringUtils.isEmpty(sTmp)?Double.parseDouble(sTmp):l.getPercentuale());
+
+          System.out.println("QA {" + l.getQa() + "}: ");
+          sTmp = inp.readLine();
+          l.setQa(!StringUtils.isEmpty(sTmp)?Integer.parseInt(sTmp):l.getQa());
+
+          System.out.println("QV {" + l.getQv() + "}: ");
+          sTmp = inp.readLine();
+          l.setQv(!StringUtils.isEmpty(sTmp)?Integer.parseInt(sTmp):l.getQv());
+
+          System.out.println("Tags [separati da virgola] {"+l.getTag()+"}: ");
+          sTmp = inp.readLine();
+          l.setTag(!StringUtils.isEmpty(sTmp)?sTmp:l.getTag());
+
+
+          //qui occorrerebbe validare
+           elclient.index(l);
+
+      }catch(Exception ex){
+          logErr(ex.getMessage());
+      }finally{
+        if(inp!=null){
+            try {
+                inp.close();
+            }catch(Exception e){}
+        }
+        if(isr!=null){
+            try {
+                isr.close();
+            }catch(Exception e){}
+        }
+      }
+    return 0;
+  }
+  private void logWarn(String msg){
+     this.logger.warn("                                        (((");
+     this.logger.warn("                                       (@ @)");
+     this.logger.warn("-----------------------------------ooO--(_)--Ooo--------------------------------");
+     this.logger.warn("| "+ StringUtils.rightPad(msg, CONSOLE_ROW_LENGHT - 3 - msg.length())                               +"|");
+     this.logger.warn("--------------------------------------------------------------------------------");
+  }
+  private void logErr(String msg){
+     this.logger.error("                                        §§§");
+     this.logger.error("                                       (+ +)");
+     this.logger.error("-----------------------------------ooO--(_)--Ooo--------------------------------");
+     this.logger.error("| "+ StringUtils.rightPad(msg, CONSOLE_ROW_LENGHT - 3 - msg.length())                               +"|");
+     this.logger.error("--------------------------------------------------------------------------------");
+  }
+
+}

+ 195 - 0
src/main/java/org/django/acquabooks/ElasticRESTClient.java

@@ -0,0 +1,195 @@
+package org.django.acquabooks;
+
+import io.searchbox.client.JestClient;
+import io.searchbox.client.JestClientFactory;
+import io.searchbox.client.JestResult;
+import io.searchbox.client.config.HttpClientConfig;
+import io.searchbox.core.*;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.django.acquabooks.pojos.Libro;
+
+
+public class ElasticRESTClient {
+   private JestClientFactory factory;
+   private JestClient client;
+
+    public static final Integer MAX_RESULTS = 1000;
+   
+
+  public static ElasticRESTClient getInstance(String protocol, String host, String port){
+    ElasticRESTClient r = new ElasticRESTClient();
+    r.setFactory(new JestClientFactory());
+    r.getFactory().setHttpClientConfig(new HttpClientConfig
+                          .Builder(protocol + "://" + host + ":" + port)
+                          .multiThreaded(true)
+                          .build());
+   
+    r.setClient(r.getFactory().getObject());
+    
+    return r;
+   
+  }
+
+  /**
+   * @return the factory
+   */
+  public JestClientFactory getFactory() {
+          return factory;
+  }
+
+  /**
+   * @param factory the factory to set
+   */
+  public void setFactory(JestClientFactory factory) {
+          this.factory = factory;
+  }
+
+  /**
+   * @return the client
+   */
+  public JestClient getClient() {
+          return client;
+  }
+
+  /**
+   * @param client the client to set
+   */
+  public void setClient(JestClient client) {
+          this.client = client;
+  }
+
+
+  public Libro getDetail(String barcode) throws IOException {
+    Get get = new Get.Builder("acquatorbida", barcode).type("libro").build();
+    JestResult result = client.execute(get);
+    if(result.isSucceeded()){
+      return result.getSourceAsObject(Libro.class);
+    }
+    return null;
+  }
+
+    public boolean delete(String barcode) throws IOException {
+     JestResult result = client.execute(new Delete.Builder(barcode)
+                .index("acquatorida")
+                .type("libro")
+                .build());
+
+        return result.isSucceeded();
+
+    }
+
+  public Boolean index(Libro l) throws IOException {
+        return this.index(l,Boolean.TRUE);
+  }
+  public Boolean index(Libro l, Boolean updateDate) throws IOException {
+    if(updateDate) {
+     l.setUltimoAggiornamento(System.currentTimeMillis());
+    }
+    Index index = new Index.Builder(l).index("acquatorbida").type("libro").build();
+    JestResult r = client.execute(index);
+    return r.isSucceeded();
+  }
+
+
+    public List<Libro> getAll() throws IOException {
+
+        String query = "{" +
+                "\"query\": {" +
+                     "\"match_all\": {}" +
+                "}" +
+             "}";
+
+        Search search = new Search.Builder(query)
+                // multiple index or types can be added.
+                .addIndex("acquatorbida")
+                //        .setSearchType(SearchType.COUNT)
+                .setParameter("size", MAX_RESULTS)
+                .build();
+
+
+        SearchResult result = client.execute(search);
+        //result.getTotal()
+        return  result.getSourceAsObjectList(Libro.class);
+    }
+
+    public List<Libro> getByPublisher(String publisher) throws IOException {
+
+        String query = "{" +
+                "\"query\": {" +
+                            "  \"multi_match\": {" +
+
+                                "\"query\":" +
+                                    "\"" + publisher +"\"," +
+                                "\"fields\":" +
+                                    "[ \"editore\", \"tag\" ]" +
+                "               }" +
+                //     "\"match\": {" +
+                //            "\"editore\":\""+publisher+"\""+
+                //        "}" +
+                "}" +
+             "}";
+
+        Search search = new Search.Builder(query)
+                // multiple index or types can be added.
+                .addIndex("acquatorbida").addType("libro")
+                //        .setSearchType(SearchType.COUNT)
+                .setParameter("size", MAX_RESULTS)
+                .build();
+
+
+        SearchResult result = client.execute(search);
+        //result.getTotal()
+        return  result.getSourceAsObjectList(Libro.class);
+
+    }
+
+    public List<Libro> getVendutoByPublisher(String publisher) throws IOException {
+        //in range lt è un numero alto (per i volumi di acquatorbida) a caso
+        String query = "{\"query\" : {" +
+                "      \"bool\" : {" +
+                "         \"must\" : [" +
+                "            {" +
+                            "  \"multi_match\": {" +
+
+                                "\"query\":" +
+                                    "\"" + publisher +"\"," +
+                                "\"fields\":" +
+                                    "[ \"editore\", \"tag\" ]" +
+                "               }" +
+                            "}," +
+
+
+//               "            {" +
+//                "               \"term\" : {" +
+//                "                  \"editore\" : \""+ publisher + "\""+
+//                "                 }" +
+//                "            }," +
+
+
+                "            {" +
+                "              \"range\" : {" +
+                "                \"qv\" : { \"gt\" : 0, \"lt\" : 20000 }" +
+                "               }" +
+                "            }" +
+                "         ]" +
+                "      }" +
+                    "}" +
+                "}";
+
+        Search search = new Search.Builder(query)
+                // multiple index or types can be added.
+                .addIndex("acquatorbida").addType("libro")
+                //        .setSearchType(SearchType.COUNT)
+                .setParameter("size", MAX_RESULTS)
+                .build();
+
+
+        SearchResult result = client.execute(search);
+        //result.getTotal()
+        return  result.getSourceAsObjectList(Libro.class);
+    }
+
+}

+ 224 - 0
src/main/java/org/django/acquabooks/ExtractionManager.java

@@ -0,0 +1,224 @@
+package org.django.acquabooks;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.django.acquabooks.io.Console;
+import org.django.acquabooks.pojos.Libro;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.reflect.TypeToken;
+import com.google.gson.stream.JsonWriter;
+
+
+/**
+ * Created by conte on 25/08/15.
+ */
+public class ExtractionManager {
+
+    /*
+    extract all books
+     */
+    public static final String TYPE_ALL = "T";
+    public static final String TYPE_BY_PUBLISHER = "E";
+    public static final String TYPE_VENDUTO_BY_PUBLISHER = "VE";
+
+    public static final String COMMAND_PARAMETERS_SEPARATOR = ",";
+    public static final String COMMAND_PARAMETERS_ASSIGNATION = ":";
+    public static final String JSON_EXTRACTION_TYPE = "json";
+    public static final String EXCEL_EXTRACTION_TYPE = "excel";
+
+    public static int CONSOLE_ROW_LENGHT = 80;
+
+    private static final Logger logger = LoggerFactory
+            .getLogger(CommandLineLauncher.class);
+
+    private ElasticRESTClient elclient;
+
+    private String commandString;
+
+
+
+    public ExtractionManager(ElasticRESTClient elclient, String command) {
+        this.elclient = elclient;
+        this.commandString = command;
+    }
+
+    public ExtractionManager(ElasticRESTClient elclient) {
+        this.elclient = elclient;
+        this.commandString = ExtractionManager.TYPE_ALL;
+    }
+
+    public boolean run(){
+        DateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
+
+        String filename = "";
+        List<Libro> r = null;
+        File fout = null;
+        JsonWriter writer = null;
+        try {
+
+
+            if(commandString.startsWith(TYPE_ALL)){
+                r = elclient.getAll();
+                filename += TYPE_ALL + "_";
+            }else if(commandString.startsWith(TYPE_BY_PUBLISHER)){
+                r = elclient.getByPublisher(getPublisher());
+                filename += TYPE_BY_PUBLISHER + "_" + getPublisher() + "_";
+            }else if(commandString.startsWith(TYPE_VENDUTO_BY_PUBLISHER)){
+                r = elclient.getVendutoByPublisher(getPublisher());
+                filename += TYPE_VENDUTO_BY_PUBLISHER + "_" + getPublisher() + "_";
+            }
+
+            filename += df.format(new Date());
+
+            if(isJsonExtraction()){
+                filename += ".json";
+                fout =  new File(filename);
+                fout.createNewFile();
+                writer = new JsonWriter(new FileWriter(fout));
+                writer.setIndent("  ");
+                Gson g = new GsonBuilder().setPrettyPrinting().create();
+                g.toJson(r,new TypeToken<Collection<Libro>>(){}.getType(),writer);
+                logger.info("Created file: " + filename);
+            } else if(isExcelExtraction()){
+                filename += ".xls";
+                fout =  new File(filename);
+                fout.createNewFile();
+                manageExcelExtraction(fout, r);
+            }
+                Console.genericWarn("Creato file: "+fout.getAbsolutePath());
+                } catch (Throwable e) {
+                        logger.error("Error on extracting data: " + e.getMessage());
+                        e.printStackTrace();
+                } finally {
+                        if(writer !=null){
+                         try {
+                            writer.flush();
+                            writer.close();
+                          } catch(Exception e){
+                                  e.printStackTrace();
+                          }
+                        }
+                }
+                return true;
+        }
+
+        private void manageExcelExtraction(File fout, List<Libro> r) {
+          FileOutputStream fileOut = null;
+          try{
+            HSSFWorkbook wb = new HSSFWorkbook();
+            fileOut = new FileOutputStream(fout);
+            Sheet sheet = wb.createSheet("Estrazione");
+            int rowCount = 0;
+           //headers
+            Row row = sheet.createRow(rowCount++);
+            Cell c = row.createCell(0);
+            c.setCellValue("ISBN");
+            c = row.createCell(1);
+            c.setCellValue("EDITORE");
+            c = row.createCell(2);
+            c.setCellValue("AUTORE");
+            c = row.createCell(3);
+            c.setCellValue("TITOLO");
+            c = row.createCell(4);
+            c.setCellValue("PREZZO");
+            c = row.createCell(5);
+            c.setCellValue("PERCENTUALE");
+            c = row.createCell(6);
+            c.setCellValue("Qta stock");
+            c = row.createCell(7);
+            c.setCellValue("Qta venduta");
+            c = row.createCell(8);
+            c.setCellValue("TAG");
+            c = row.createCell(9);
+            c.setCellValue("DA VERSARE");
+              for (Libro l: r) {
+                  row = sheet.createRow(rowCount++);
+                  c = row.createCell(0);
+                  c.setCellValue(l.getBarcode());  
+                  c = row.createCell(1);
+                  c.setCellValue(l.getEditore());
+                  c = row.createCell(2);
+                  c.setCellValue(l.getAutore());
+                  c = row.createCell(3);
+                  c.setCellValue(l.getTitolo());
+                  c = row.createCell(4);
+                  c.setCellValue(l.getPrezzo());
+                  c = row.createCell(5);
+                  c.setCellValue(l.getPercentuale());
+                  c = row.createCell(6);
+                  c.setCellValue(l.getQa()-l.getQv());
+                  c = row.createCell(7);
+                  c.setCellValue(l.getQv());
+                  c = row.createCell(8);
+                  c.setCellValue(l.getTag());
+                  c = row.createCell(9);
+                  c.setCellFormula("H" + rowCount + "*(E" + rowCount +"-(E" + rowCount + "*F" + rowCount + "))");
+
+              }
+              row = sheet.createRow(rowCount++);
+              row = sheet.createRow(rowCount++);
+              c = row.createCell(8);
+              c.setCellValue("TOTALE: ");
+              c = row.createCell(9);
+//              c.setCellFormula("SUM(J2:J+" + (rowCount-2) + ")");
+
+            wb.write(fileOut);
+
+          }catch(Exception e) {
+            e.printStackTrace();
+          }finally{
+            try {
+              fileOut.close();
+            } catch(Exception e){
+                    e.printStackTrace();
+            }
+
+          }
+        
+
+        }
+
+        private boolean isExcelExtraction(){
+        if(!StringUtils.isEmpty(commandString)){
+            String[] parts = commandString.split(COMMAND_PARAMETERS_SEPARATOR);
+            return parts[parts.length-1].equals(EXCEL_EXTRACTION_TYPE);
+        }
+
+        return false;
+    }
+
+    private boolean isJsonExtraction(){
+        if(!StringUtils.isEmpty(commandString)){
+            String[] parts = commandString.split(COMMAND_PARAMETERS_SEPARATOR);
+            return parts[parts.length-1].equals(JSON_EXTRACTION_TYPE);
+        }
+
+        return false;
+    }
+
+    private String getPublisher(){
+        if(!StringUtils.isEmpty(commandString)){
+            String[] parts = commandString.split(COMMAND_PARAMETERS_SEPARATOR);
+            return parts[1];
+        }
+
+        return null;
+    }
+
+}

+ 166 - 0
src/main/java/org/django/acquabooks/ImportManager.java

@@ -0,0 +1,166 @@
+package org.django.acquabooks;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Date;
+import java.util.Scanner;
+
+import com.google.gson.stream.JsonReader;
+import org.apache.commons.lang3.StringUtils;
+import org.django.acquabooks.io.Console;
+import org.django.acquabooks.pojos.Libro;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.gson.Gson;
+
+public class ImportManager {
+  public static int CONSOLE_ROW_LENGHT = 80;
+
+
+
+  public static int MODE_INSERT = 0;
+  public static int MODE_EDIT = 1;
+  public static int MODE_AZZERA_VENDUTO = 2;
+
+  private static final Logger logger = LoggerFactory
+                  .getLogger(CommandLineLauncher.class);
+
+  private ElasticRESTClient elclient;
+
+  private File fileIn;
+
+  // se MODE_EDIT una volta settato rimane, il  che impedisce all'oggetto di essere
+  // un singleton usabile sia per gli import che gli export, ritenuto che
+  // non è in previsione una versione ad interfaccia grafica stile ncurses
+  // o swing o altro, si è ritenuto che via command line "one shot" ogni azione
+  // crea un nuovo oggetto e lo termina. 
+  private int mode;
+
+  public ImportManager(String filename) {
+          elclient = ElasticRESTClient.getInstance("http", "localhost", "9200");
+          fileIn = new File(filename);
+  }
+
+  /*
+   * default: is an Import
+  */
+  public ImportManager(String filename,  ElasticRESTClient client){
+    this.elclient = client;
+    this.fileIn = new File(filename);
+    this.mode = MODE_INSERT;
+  }
+
+
+  public ImportManager(String filename, int mode , ElasticRESTClient client){
+    this.elclient = client;
+    this.fileIn = new File(filename);
+    this.mode = mode;
+  }
+
+  public void run(){
+      JsonReader reader = null;
+      try {
+          Gson gson = new Gson();
+
+          reader = new JsonReader(new FileReader(fileIn));
+          reader.beginArray();
+          while (reader.hasNext()) {
+
+            Libro lin = new Libro();
+            reader.beginObject();
+               while (reader.hasNext()) {
+                String prop = reader.nextName();
+                 switch (prop){
+                    case "barcode":
+                        lin.setBarcode(reader.nextString());
+                        break;
+                    case "editore":
+                        lin.setEditore(reader.nextString());
+                        break;
+                    case "tag":
+                        lin.setTag(reader.nextString());
+                        break;
+                    case "autore":
+                        lin.setAutore(reader.nextString());
+                        break;
+                    case "titolo":
+                        lin.setTitolo(reader.nextString());
+                        break;
+                    case "prezzo":
+                        lin.setPrezzo(reader.nextDouble());
+                        break;
+                    case "percentuale":
+                        lin.setPercentuale(reader.nextDouble());
+                        break;
+                    case "qa":
+                        lin.setQa(((int) reader.nextLong()));
+                        break;
+                    case "qv":
+                        lin.setQv(((int) reader.nextLong()));
+                        break;
+                    case "sconto":
+                        lin.setSconto(reader.nextDouble());
+                        break;
+                    default:
+                        reader.skipValue();
+                        break;
+                }
+               }
+            reader.endObject();
+            if(mode == MODE_INSERT || mode == MODE_AZZERA_VENDUTO){
+              Libro l = elclient.getDetail(lin.getBarcode());
+              if(l != null && MODE_INSERT == mode){
+                  logErr("FALLITO record già presente!! Barcode: "+l.getBarcode());
+                  continue;
+              }
+              if(l == null && MODE_AZZERA_VENDUTO == mode){
+                  logErr("FALLITO libro NON presente!! Barcode: "+l.getBarcode());
+                  continue;
+              }else if(MODE_AZZERA_VENDUTO == mode){ //l !=null is implicit
+                  l.setQa(l.getQa() - l.getQv());
+                  l.setQv(0);
+                  lin = l;
+              }
+
+            }
+            if(elclient.index(lin)){
+                Console.genericWarn("Indicizzato record con barcode: " + lin.getBarcode());
+            }else{
+                Console.genericErr("FALLITO record con barcode: " + lin.getBarcode());
+            }
+          }
+          reader.endArray();
+      } catch (FileNotFoundException e) {
+          e.printStackTrace();
+      } catch (IOException e) {
+          e.printStackTrace();
+      }finally {
+          try {
+              reader.close();
+          } catch (IOException e) {
+              logger.error("Error on closing reader",e);
+          }
+      }
+  }
+
+  private void logWarn(String msg){
+     this.logger.warn("                                        (((");
+     this.logger.warn("                                       (@ @)");
+     this.logger.warn("-----------------------------------ooO--(_)--Ooo--------------------------------");
+     this.logger.warn("| "+ StringUtils.rightPad(msg, CONSOLE_ROW_LENGHT - 3 - msg.length())                               +"|");
+     this.logger.warn("--------------------------------------------------------------------------------");
+  }
+
+  private void logErr(String msg){
+     this.logger.error("                                        §§§");
+     this.logger.error("                                       (+ +)");
+     this.logger.error("-----------------------------------ooO--(_)--Ooo--------------------------------");
+     this.logger.error("| "+ StringUtils.rightPad(msg, CONSOLE_ROW_LENGHT - 3 - msg.length())                               +"|");
+     this.logger.error("--------------------------------------------------------------------------------");
+        }
+
+
+}

+ 107 - 0
src/main/java/org/django/acquabooks/SellingManager.java

@@ -0,0 +1,107 @@
+package org.django.acquabooks;
+
+import org.apache.commons.lang3.StringUtils;
+import org.django.acquabooks.io.Console;
+import org.django.acquabooks.pojos.Libro;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Scanner;
+
+public class SellingManager {
+    private static final Logger logger = LoggerFactory.getLogger(CommandLineLauncher.class);
+    public static  String STOP_READING_SEQUENCE = "q";
+    public static  int DEFAULT_OP_AMOUNT = 1;
+    public static  String COMMAND = ":";
+    private ElasticRESTClient elclient;
+
+
+    public  SellingManager(){
+        elclient = ElasticRESTClient.getInstance("http","localhost", "9200");
+    }
+
+    public  SellingManager(ElasticRESTClient client){
+        elclient = client;
+    }
+
+    public void run(){
+        String in = null;
+        Console.welcome(System.out,"ACQUATORPIDA BOOK SHOCKS - SPARA VENDERE");
+        Scanner sc = new Scanner(System.in);
+        int opAmount = DEFAULT_OP_AMOUNT;
+        while (sc.hasNextLine()) {
+            in = sc.nextLine();
+            if(STOP_READING_SEQUENCE.equals(in)){
+                return;
+            }
+
+            if(StringUtils.isEmpty(in)){
+                continue;
+            }
+
+            if(in.startsWith(COMMAND)){
+                String[] parts = in.split(COMMAND);
+                try {
+                    opAmount = Integer.parseInt(parts[1]);
+                }catch(Throwable e){
+                    Console.genericErr("NUMERO NON VALIDO");
+                    opAmount = DEFAULT_OP_AMOUNT;
+                }
+                continue;
+            }
+
+            try {
+                Libro l = elclient.getDetail(in);
+                if(l == null){
+                    Console.genericWarn("LIBRO NON TROVATO: " + in);
+                    opAmount = DEFAULT_OP_AMOUNT;
+                    continue;
+                }
+                l.incrementaVenduto(opAmount);
+
+                boolean r = elclient.index(l, opAmount != 0);
+                if(!r){
+                    Console.genericErr("Errore in aggiornamento");
+                }else{
+                    Console.ok(System.out);
+                    Console.detail(l, System.out);
+                }
+                opAmount = DEFAULT_OP_AMOUNT;
+            } catch(Exception e){
+                logger.error(e.getMessage());
+                e.printStackTrace();
+            }
+        }
+    }
+    public void runDetail(){
+        String in = null;
+        Console.welcome(System.out,"ACQUATORBIDA BOOK CHOC - SPARA PER IL DETTAGLIO");
+        Scanner sc = new Scanner(System.in);
+        int lineNumber = 0;
+        while (sc.hasNextLine()) {
+            in = sc.nextLine();
+            if(STOP_READING_SEQUENCE.equals(in)){
+                return;
+            }
+
+            if(StringUtils.isEmpty(in)){
+                continue;
+            }
+            try {
+                Libro l = elclient.getDetail(in);
+                if(l == null){
+                    Console.genericWarn("LIBRO NON TROVATO: " + in);
+                }else{
+                    Console.ok(System.out);
+                    System.out.println(l.toString());
+                }
+
+            } catch(Exception e){
+                e.printStackTrace();
+            }
+        }
+    }
+
+
+
+}

+ 430 - 0
src/main/java/org/django/acquabooks/io/Ansi.java

@@ -0,0 +1,430 @@
+/**
+ * JLibs: Common Utilities for Java
+ * Copyright (C) 2009  Santhosh Kumar T <santhosh.tekuri@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+package org.django.acquabooks.io;
+import org.django.acquabooks.utils.OS;
+
+import java.io.PrintStream;
+
+/**
+ * Ansi coloring support is provided by this class. <p> To print "hello ansi world" in bold with blue foreground and white background: <pre> Ansi ansi = new
+ * Ansi(Ansi.Attribute.BRIGHT, Ansi.Color.BLUE, Ansi.Color.WHITE); ansi.{@link #out(String) out}("hello ansi world") </pre>
+ *
+ * same can be done as below: <pre> String msg = ansi.{@link #colorize(String) colorize}("hello ansi world"); // msg is original string wrapped with ansi
+ * control sequences System.out.println(msg); </pre>
+ *
+ * <b>Ansi Support:</b> <p> Ansi might not be supported on all systems. Ansi is mostly supported by all unix operating systems. <br><br> {@link Ansi#SUPPORTED}
+ * is a final boolean, that can be used to check whether your console supports Ansi format; <br><br> Ansi class uses simple checks to decide whether ansi is
+ * supported or not. Sometimes it may do wrong guess. In such cases you can override its decision using following system property: <code>-DAnsi=true</code> or
+ * <code>-DAnsi=false</code> <br><br> if {@link Ansi#SUPPORTED} is false, any ansi method will not produce ansi control sequences. so you can safely use:
+ * <code>ansi.out("hello ansi world")</code> irrespective of ansi is supported or not. if ansi is not supported, this will simply do
+ * <code>System.out.print("hello ansi world")</code>
+ *
+ * @author Santhosh Kumar T
+ */
+public class Ansi {
+    /**
+     * specifies whether ansi is supported or not. <p><br> when this is false, it doesn't colorize given strings, rather than simply returns the given strings
+     * <p><br> It tries best effort to guess whether ansi is supported or not. But you can override this value using system property "Ansi" (-DAnsi=true/false)
+     */
+    public static final boolean SUPPORTED = Boolean.getBoolean("Ansi") || OS.get().isUnix() && System.console() != null;
+
+    /**
+     * this enum represents the attribute of text
+     */
+    public enum Attribute {
+        /**
+         * Reset All Attributes (return to normal mode)
+         */
+        NORMAL(0),
+        /**
+         * Usually turns on BOLD
+         */
+        BRIGHT(1),
+        DIM(2),
+        UNDERLINE(4),
+        BLINK(5),
+        /**
+         * Reverse video on
+         */
+        REVERSE(7),
+        /**
+         * Concealed on
+         */
+        HIDDEN(8);
+
+        private final String value;
+
+        private Attribute(final int value) {
+            this.value = String.valueOf(value);
+        }
+
+        public String toString() {
+            return "" + value;
+        }
+    }
+
+    /**
+     * this enum represents the color of text
+     */
+    public enum Color {
+        BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE
+    }
+
+    public final static class AnsiColor {
+        public final static AnsiColor BLACK = new AnsiColor(Color.BLACK);
+        public final static AnsiColor RED = new AnsiColor(Color.RED);
+        public final static AnsiColor GREEN = new AnsiColor(Color.GREEN);
+        public final static AnsiColor YELLOW = new AnsiColor(Color.YELLOW);
+        public final static AnsiColor BLUE = new AnsiColor(Color.BLUE);
+        public final static AnsiColor MAGENTA = new AnsiColor(Color.MAGENTA);
+        public final static AnsiColor CYAN = new AnsiColor(Color.CYAN);
+        public final static AnsiColor WHITE = new AnsiColor(Color.WHITE);
+
+        private final int _colorIndex;
+        private final Color _standardColor;
+
+        public AnsiColor(final int colorIndex) {
+            _colorIndex = colorIndex;
+            _standardColor = null;
+        }
+
+        public AnsiColor(final Color standardColor) {
+            _colorIndex = -1;
+            _standardColor = standardColor;
+        }
+
+        public final int getColorIndex() {
+            return _colorIndex;
+        }
+
+        public final boolean isStandardColor() {
+            return _standardColor != null;
+        }
+
+        public final Color getStandardColor() {
+            return _standardColor;
+        }
+
+        public static AnsiColor forStandardColor(final Color color) {
+            if (color == null) {
+                return null;
+            }
+
+            switch (color) {
+                case BLACK:
+                    return BLACK;
+                case RED:
+                    return RED;
+                case GREEN:
+                    return GREEN;
+                case YELLOW:
+                    return YELLOW;
+                case BLUE:
+                    return BLUE;
+                case MAGENTA:
+                    return MAGENTA;
+                case CYAN:
+                    return CYAN;
+                case WHITE:
+                    return WHITE;
+                default:
+                    return new AnsiColor(color);
+            }
+        }
+    }
+
+    private static final String PREFIX = "\u001b["; //NOI18N
+    private static final String SUFFIX = "m";
+    private static final String XTERM_256_SEPARATOR = "5;";
+    private static final String SEPARATOR = ";";
+    private static final String END = PREFIX + SUFFIX;
+
+    private String start = "";
+
+    /**
+     * Creates new instanceof Ansi.
+     *
+     * @param attr attribute of text, null means don't change
+     * @param foreground foreground color of text, null means don't change
+     * @param background background color of text, null means don't change
+     */
+    public Ansi(final Attribute attr, final Color foreground, final Color background) {
+        init(attr, AnsiColor.forStandardColor(foreground), AnsiColor.forStandardColor(background));
+    }
+
+    /**
+     * Creates new instanceof Ansi.
+     *
+     * @param attr attribute of text, null means don't change
+     * @param foreground foreground color of text, null means don't change
+     * @param background background color of text, null means don't change
+     */
+    public Ansi(final Attribute attr, final AnsiColor foreground, final AnsiColor background) {
+        init(attr, foreground, background);
+    }
+
+    /**
+     * Creates new instanceof of ansi with specified format.<p> The format syntax is
+     * <pre>
+     * Attribute[;Foreground[;Background]]
+     * </pre>
+     * i.e, semicolon(;) separated values, where tokens are attribute, foreground and background respectively.<br> if any non-trailing token in value is null,
+     * you still need to specify empty value. for example:
+     * <pre>
+     * DIM;;GREEN # foreground is not specified
+     * </pre>
+     */
+    public Ansi(final String format) {
+        final String[] tokens = format.split(";");
+
+        Ansi.Attribute attribute = null;
+        try {
+            if (tokens.length > 0 && tokens[0].length() > 0) {
+                attribute = Ansi.Attribute.valueOf(tokens[0]);
+            }
+        }
+        catch (IllegalArgumentException ex) {
+            ex.printStackTrace();
+        }
+
+        Ansi.Color foreground = null;
+        try {
+            if (tokens.length > 1 && tokens[1].length() > 0) {
+                foreground = Ansi.Color.valueOf(tokens[1]);
+            }
+        }
+        catch (IllegalArgumentException e) {
+            e.printStackTrace();
+        }
+
+        Ansi.Color background = null;
+        try {
+            if (tokens.length > 2 && tokens[2].length() > 0) {
+                background = Ansi.Color.valueOf(tokens[2]);
+            }
+        }
+        catch (IllegalArgumentException e) {
+            e.printStackTrace();
+        }
+
+        init(attribute, AnsiColor.forStandardColor(foreground), AnsiColor.forStandardColor(background));
+    }
+
+    private void init(final Attribute attr, final AnsiColor foreground, final AnsiColor background) {
+        final StringBuilder buff = new StringBuilder();
+
+        if (attr != null) {
+            buff.append(attr);
+        }
+
+        if (foreground != null) {
+            if (buff.length() > 0) {
+                buff.append(SEPARATOR);
+            }
+            if (foreground.isStandardColor()) {
+                buff.append(30 + foreground._standardColor.ordinal());
+            }
+            else {
+                buff.append(38).append(SEPARATOR).append(XTERM_256_SEPARATOR).append(foreground._colorIndex);
+            }
+        }
+        if (background != null) {
+            if (buff.length() > 0) {
+                buff.append(SEPARATOR);
+            }
+            if (background.isStandardColor()) {
+                buff.append(40 + background._standardColor.ordinal());
+            }
+            else {
+                buff.append(48).append(SEPARATOR).append(XTERM_256_SEPARATOR).append(background._colorIndex);
+            }
+        }
+        buff.insert(0, PREFIX);
+        buff.append(SUFFIX);
+
+        start = buff.toString();
+    }
+
+    /**
+     * The string representation of this object. This string will be the same that is expected by {@link #Ansi(String)}
+     *
+     * @return string representation of this object
+     */
+    @Override
+    public String toString() {
+        Attribute attr = null;
+        Color foreground = null;
+        Color background = null;
+
+        for (final String token : start.substring(PREFIX.length(), start.length() - SUFFIX.length()).split(SEPARATOR)) {
+            final int i = Integer.parseInt(token);
+            if (i < 30) {
+                for (final Attribute value : Attribute.values()) {
+                    if (value.toString().equals(token)) {
+                        attr = value;
+                        break;
+                    }
+                }
+            }
+            else if (i < 40) {
+                foreground = Color.values()[i - 30];
+            }
+            else {
+                background = Color.values()[i - 40];
+            }
+        }
+
+        final StringBuilder buff = new StringBuilder();
+        if (attr != null) {
+            buff.append(attr.name());
+        }
+        buff.append(';');
+        if (foreground != null) {
+            buff.append(foreground.name());
+        }
+        buff.append(';');
+        if (background != null) {
+            buff.append(background.name());
+        }
+
+        int end = buff.length() - 1;
+        while (end >= 0 && buff.charAt(end) == ';') {
+            end--;
+        }
+        return buff.substring(0, end + 1);
+    }
+
+    /**
+     * Wraps given <code>message</code> with special ansi control sequences and returns it
+     */
+    public String colorize(final String message) {
+        if (SUPPORTED) {
+            final StringBuilder buff = new StringBuilder(start.length() + message.length() + END.length());
+            buff.append(start).append(message).append(END);
+            return buff.toString();
+        }
+        else {
+            return message;
+        }
+    }
+
+    /*-------------------------------------------------[ Printing ]---------------------------------------------------*/
+
+    /**
+     * Prints colorized {@code message} to specified {@code ps}. <p> if {@link #SUPPORTED} is false, it prints raw {@code message} to {@code ps}
+     *
+     * @param ps stream to print
+     * @param message message to be colorized
+     */
+    public void print(final PrintStream ps, final String message) {
+        if (SUPPORTED) {
+            ps.print(start);
+        }
+        ps.print(message);
+        if (SUPPORTED) {
+            ps.print(END);
+        }
+    }
+
+    /**
+     * Prints colorized {@code message} to specified {@code ps} followed by newline. <p> if {@link #SUPPORTED} is false, it prints raw {@code message} to {@code
+     * ps} followed by newline.
+     *
+     * @param ps stream to print
+     * @param message message to be colorized
+     */
+    public void println(final PrintStream ps, final String message) {
+        print(ps, message);
+        ps.println();
+    }
+
+    /**
+     * Prints formatted and colorized {@code message} to specified {@code ps}. <p> if {@link #SUPPORTED} is false, it prints formatted {@code message} to {@code
+     * ps}
+     *
+     * @param ps stream to print
+     * @param format A format string whose output to be colorized
+     * @param args Arguments referenced by the format specifiers in the format
+     */
+    public void format(final PrintStream ps, final String format, final Object... args) {
+        if (SUPPORTED) {
+            ps.print(start);
+        }
+        ps.format(format, args);
+        if (SUPPORTED) {
+            ps.print(END);
+        }
+    }
+
+    /*-------------------------------------------------[ System.out ]---------------------------------------------------*/
+
+    /**
+     * Prints colorized {@code message} to {@link System#out}
+     *
+     * @param message message to be colorized
+     */
+    public void out(final String message) {
+        print(System.out, message);
+    }
+
+    /**
+     * Prints colorized {@code message} to {@link System#out} followed by newline
+     *
+     * @param message message to be colorized
+     */
+    public void outLine(final String message) {
+        println(System.out, message);
+    }
+
+    /**
+     * Prints formatted and colorized {@code format} to {@link System#out}
+     *
+     * @param format A format string whose output to be colorized
+     * @param args Arguments referenced by the format specifiers in the format
+     */
+    public void outFormat(final String format, final Object... args) {
+        format(System.out, format, args);
+    }
+
+    /*-------------------------------------------------[ System.err ]---------------------------------------------------*/
+
+    /**
+     * Prints colorized {@code message} to {@link System#err}
+     *
+     * @param message message to be colorized
+     */
+    public void err(final String message) {
+        print(System.err, message);
+    }
+
+    /**
+     * Prints colorized {@code message} to {@link System#err} followed by newline
+     *
+     * @param message message to be colorized
+     */
+    public void errLine(final String message) {
+        print(System.err, message);
+    }
+
+    /**
+     * Prints formatted and colorized {@code format} to {@link System#err}
+     *
+     * @param format A format string whose output to be colorized
+     * @param args Arguments referenced by the format specifiers in the format
+     */
+    public void errFormat(final String format, final Object... args) {
+        format(System.err, format, args);
+    }
+}

+ 146 - 0
src/main/java/org/django/acquabooks/io/Console.java

@@ -0,0 +1,146 @@
+package org.django.acquabooks.io;
+
+import org.apache.commons.lang3.StringUtils;
+import org.django.acquabooks.pojos.Libro;
+
+import java.io.PrintStream;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * Created by conte on 16/10/15.
+ */
+public class Console {
+
+  public static DateFormat TS_DATE_FORMAT =  new SimpleDateFormat("YYYYddMMHHmmss");
+  public static DateFormat READABLE_DATE_FORMAT =  new SimpleDateFormat("dd.MM.YYYY HH:mm:ss");
+
+
+  public static  int CONSOLE_ROW_LENGHT = 80;
+  private static PrintStream out;
+
+  public static void genericWarn(String msg) {
+    genericWarn(System.out,msg);
+  }
+  public static void genericWarn(PrintStream out, String msg){
+
+    out.println("                                        (((");
+    out.println("                                       (@ @)");
+    out.println("-----------------------------------ooO--(_)--Ooo--------------------------------");
+    out.println("| "+ StringUtils.rightPad(msg, CONSOLE_ROW_LENGHT - 3 - msg.length())                               +"|");
+    out.println("--------------------------------------------------------------------------------");
+  }
+  public static void genericErr(String msg) {
+    genericErr(System.err, msg);
+  }
+  public static void genericErr(PrintStream out, String msg){
+    out.println("                                        §§§");
+    out.println("                                       (+ +)");
+    out.println("-----------------------------------ooO--(_)--Ooo--------------------------------");
+    out.println("| "+ StringUtils.rightPad(msg, CONSOLE_ROW_LENGHT - 3 - msg.length())                               +"|");
+    out.println("--------------------------------------------------------------------------------");
+  }
+  public static void ok(PrintStream out){
+
+
+    Ansi a = new Ansi(null, Ansi.AnsiColor.GREEN, null);
+    a.outLine("     OOOOOOOOO     KKKKKKKKK    KKKKKKK");
+    a = new Ansi(null, Ansi.AnsiColor.BLUE, null);
+    a.outLine("   OO:::::::::OO   K:::::::K    K:::::K");
+    a = new Ansi(null, Ansi.AnsiColor.YELLOW, null);
+    a.outLine(" OO:::::::::::::OO K:::::::K    K:::::K");
+    a = new Ansi(null, Ansi.AnsiColor.WHITE, null);
+    a.outLine("::::::OOO:::::::OK:::::::K   K::::::K");
+    a = new Ansi(null, Ansi.AnsiColor.MAGENTA, null);
+    a.outLine(":::::O   O::::::OKK::::::K  K:::::KKK");
+    a = new Ansi(null, Ansi.AnsiColor.CYAN, null);
+    a.outLine("::::O     O:::::O  K:::::K K:::::K   ");
+    a = new Ansi(null, Ansi.AnsiColor.RED, null);
+    a.outLine("::::O     O:::::O  K::::::K:::::K    ");
+    a = new Ansi(null, Ansi.AnsiColor.BLUE, null);
+    a.outLine("::::O     O:::::O  K:::::::::::K     ");
+    a = new Ansi(null, Ansi.AnsiColor.YELLOW, null);
+    a.outLine("::::O     O:::::O  K:::::::::::K     ");
+    a = new Ansi(null, Ansi.AnsiColor.MAGENTA, null);
+    a.outLine("::::O     O:::::O  K::::::K:::::K    ");
+    a = new Ansi(null, Ansi.AnsiColor.GREEN, null);
+    a.outLine("::::O     O:::::O  K:::::K K:::::K   ");
+    a = new Ansi(null, Ansi.AnsiColor.WHITE, null);
+    a.outLine(":::::O   O::::::OKK::::::K  K:::::KKK");
+    a = new Ansi(null, Ansi.AnsiColor.RED, null);
+    a.outLine("::::::OOO:::::::OK:::::::K   K::::::K");
+    a = new Ansi(null, Ansi.AnsiColor.YELLOW, null);
+    a.outLine(" OO:::::::::::::OO K:::::::K    K:::::K");
+    a = new Ansi(null, Ansi.AnsiColor.BLUE, null);
+    a.outLine("   OO:::::::::OO   K:::::::K    K:::::K");
+    a = new Ansi(null, Ansi.AnsiColor.MAGENTA, null);
+    a.outLine("     OOOOOOOOO     KKKKKKKKK    KKKKKKK");
+    a = new Ansi(null, Ansi.AnsiColor.BLUE, null);
+    a.outLine("                                       ");
+
+  }
+  public static void welcome(PrintStream out){
+
+    welcome(out,"ACQUATORPIDA BOOK SHOCK");
+
+  }
+
+  public static void welcome(PrintStream out, String msg){
+    Ansi a = new Ansi(Ansi.Attribute.BLINK, Ansi.AnsiColor.GREEN, null);
+    out.print("           ");
+    out.print("HH");
+    out.println();
+    out.println("           HH");
+    out.println(" BBB       HH                                        ,z.");
+    out.println(" === .___. HH     %%%%                   .o.       ,zZZZ>");
+    out.println(" BBB |   | HH 838 \\\\\\\\ EEE    AAAAA     ,0X0'    ,zZZZ");
+    out.println(" BBB |<<<| HH 838 %%%% EEE ## DDDDD    ,0X0'   ,zZZZ");
+
+    a = new Ansi(Ansi.Attribute.BLINK, Ansi.AnsiColor.YELLOW, null);
+    out.print(" BBB | ");
+    a.out("Z");
+
+    out.println(" | HH 838 %GR% +++ ## AAAAA   ,0X0'  ,zZZZ");
+    out.print(" BBB | ");
+    a.out("T");
+    out.println(" | HH 838 %%%% EEE ## <<v>>  ,0X0' ,zZZZ");
+    out.print(" BBB | ");
+    a.out("L");
+    out.println(" | HH 838 %%%% EEE ## AAAAA ,0X0',zZZZ\"HH$HHHHHHHDDHH$HH");
+    out.println(" === |<<<| HH 838 //// EEE ## AAAAA.0X0;zZZZ\"  EE$EEEEEEEDDEE$EE");
+    out.println(" BBB |___| HH 838 %%%% EEE ## AAAAA'\"0' \"Z\"    HH$HHHHHHHDDHH$HH");
+    out.println("|                                                               |");
+    out.println("| "+ StringUtils.rightPad(msg, CONSOLE_ROW_LENGHT - 18)+"|");
+    out.println(" ---------------------------------------------------------------");
+  }
+
+  public static void main(String[] args){
+    Ansi a = new Ansi(Ansi.Attribute.BLINK, Ansi.AnsiColor.GREEN, null);
+    String msg = a.colorize("Porco dio");
+
+   // a.println(System.out, msg);
+Console.welcome(System.out,"ACQUATORPIDA BOOK SHOCK");
+  }
+
+  public static void detail(Libro l,PrintStream out){
+
+
+    Ansi a = new Ansi(Ansi.Attribute.BLINK, Ansi.AnsiColor.YELLOW, null);
+
+    out.println("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
+    out.println("Barcode:   "+l.getBarcode() + " Ultima modifica: " + READABLE_DATE_FORMAT.format(new Date(l.getUltimoAggiornamento())));
+    out.println("Titolo:   " + l.getTitolo());
+    out.println("Autore:   "+l.getAutore());
+    out.print("Prezzo:   " + l.getPrezzo() + " Prezzo Scontato: ");
+    if(l.getSconto()!=0) {
+      a.outLine(l.getPrezzoScontato().toString());
+    }else{
+      out.println(l.getPrezzoScontato());
+    }
+    out.println("QA: "+l.getQa() + " QV: " +l.getQv() + " Margine: "+ l.getPercentuale() + " Sconto: " + l.getSconto());
+
+
+    out.println("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
+  }
+}

+ 178 - 0
src/main/java/org/django/acquabooks/pojos/Libro.java

@@ -0,0 +1,178 @@
+package org.django.acquabooks.pojos;
+
+import io.searchbox.annotations.JestId;
+
+import java.util.Date;
+
+public class Libro{
+
+  @JestId
+  private String barcode;
+  private String titolo;
+  private String autore;
+  private String editore;
+  private String tag;
+  private Double prezzo;
+  private Double sconto;
+  private Double percentuale;
+  private Integer qa;
+  private Integer qv;
+  private Long ultimoAggiornamento;
+
+  
+  /**
+   * @return the editore
+   */
+  public String getEditore() {
+          return editore;
+  }
+
+  /**
+   * @param editore the editore to set
+   */
+  public void setEditore(String editore) {
+          this.editore = editore;
+  }
+
+        public String getTag() {
+        return tag;
+}
+
+public void setTag(String tag) {
+        this.tag = tag;
+}
+  @Override
+public String toString() {
+        return "Libro [barcode=" + barcode + ", editore=" + editore + ", titolo=" + titolo + ", autore="
+                        + autore + ", tag=" + tag + ", prezzo=" + prezzo + ", sconto=" + prezzo
+                        + ", percentuale=" + percentuale + ", qa=" + qa + ", qv=" + qv
+                        + "]";
+}
+
+/**
+   * @return the barcode
+   */
+  public String getBarcode() {
+          return barcode;
+  }
+
+  /**
+   * @param barcode the barcode to set
+   */
+  public void setBarcode(String barcode) {
+          this.barcode = barcode;
+  }
+
+  /**
+   * @return the titolo
+   */
+  public String getTitolo() {
+          return titolo;
+  }
+
+  /**
+   * @param titolo the titolo to set
+   */
+  public void setTitolo(String titolo) {
+          this.titolo = titolo;
+  }
+
+  /**
+   * @return the autore
+   */
+  public String getAutore() {
+          return autore;
+  }
+
+  /**
+   * @param autore the autore to set
+   */
+  public void setAutore(String autore) {
+          this.autore = autore;
+  }
+
+        /**
+   * @return the prezzo
+   */
+  public Double getPrezzo() {
+          return prezzo!=null?prezzo:-9999;
+  }
+
+  /**
+   * @param prezzo the prezzo to set
+   */
+  public void setPrezzo(Double prezzo) {
+          this.prezzo = prezzo;
+  }
+
+  /**
+   * @return the percentuale
+   */
+  public Double getPercentuale() {
+          return percentuale;
+  }
+
+  /**
+   * @param percentuale the percentuale to set
+   */
+  public void setPercentuale(Double percentuale) {
+          this.percentuale = percentuale;
+  }
+
+  /**
+   * @return the qa
+   */
+  public Integer getQa() {
+          return qa;
+  }
+
+  /**
+   * @param qa the qa to set
+   */
+  public void setQa(Integer qa) {
+    this.qa = qa;
+  }
+
+  /**
+   * @return the qv
+   */
+  public Integer getQv() {
+          return qv;
+  }
+
+  /**
+   * @param qv the qv to set
+   */
+  public void setQv(Integer qv) {
+          this.qv = qv;
+  }
+    
+  public void incrementaVenduto(int amount){
+    this.setQv(this.getQv()+ amount);
+  }
+
+
+  public Double getSconto() {
+      if(sconto == null){
+          sconto = 0D;
+      }
+     return sconto;
+  }
+
+  public void setSconto(Double sconto) {
+      this.sconto = sconto;
+  }
+
+  public Double getPrezzoScontato(){
+      return getPrezzo() - (getPrezzo() * getSconto());
+  }
+
+  public Long getUltimoAggiornamento() {
+      return ultimoAggiornamento;
+  }
+
+  public void setUltimoAggiornamento(Long ultimoAggiornamento) {
+      this.ultimoAggiornamento = ultimoAggiornamento;
+  }
+}
+

+ 28 - 0
src/main/java/org/django/acquabooks/utils/ContractUtils.java

@@ -0,0 +1,28 @@
+/*
+ * ContractUtils.java
+ *
+ * Copyright (c) 2012 Mike Strobel
+ *
+ * This source code is subject to terms and conditions of the Apache License, Version 2.0.
+ * A copy of the license can be found in the License.html file at the root of this distribution.
+ * By using this source code in any fashion, you are agreeing to be bound by the terms of the
+ * Apache License, Version 2.0.
+ *
+ * You must not remove this notice, or any other, from this software.
+ */
+package org.django.acquabooks.utils;
+
+/**
+ * @author Mike Strobel
+ */
+public final class ContractUtils {
+    private ContractUtils() {}
+
+    public static IllegalStateException unreachable() {
+        return new IllegalStateException("Code supposed to be unreachable");
+    }
+
+    public static UnsupportedOperationException unsupported() {
+        return new UnsupportedOperationException("The requested operation is not supported.");
+    }
+}

+ 94 - 0
src/main/java/org/django/acquabooks/utils/OS.java

@@ -0,0 +1,94 @@
+/**
+ * JLibs: Common Utilities for Java
+ * Copyright (C) 2009  Santhosh Kumar T <santhosh.tekuri@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+package org.django.acquabooks.utils;
+
+
+public enum OS {
+    WINDOWS_NT("Windows NT"),
+    WINDOWS_95("Windows 95"),
+    WINDOWS_98("Windows 98"),
+    WINDOWS_2000("Windows 2000"),
+    WINDOWS_VISTA("Windows Vista"),
+    WINDOWS_7("Windows 7"),
+    WINDOWS_OTHER("Windows"),
+
+    SOLARIS("Solaris"),
+    LINUX("Linux"),
+    HP_UX("HP-UX"),
+    IBM_AIX("AIX"),
+    SGI_IRIX("Irix"),
+    SUN_OS("SunOS"),
+    COMPAQ_TRU64_UNIX("Digital UNIX"),
+    MAC("Mac OS X", "Darwin"),
+    FREE_BSD("freebsd"),
+    // add new unix versions here
+
+    OS2("OS/2"),
+    COMPAQ_OPEN_VMS("OpenVMS"),
+
+    /**
+     * Unrecognized OS
+     */
+    OTHER("");
+
+    private final String names[];
+
+    private OS(final String... names) {
+        this.names = names;
+    }
+
+    /**
+     * @return true if this OS belongs to windows family
+     */
+    public boolean isWindows() {
+        return ordinal() <= WINDOWS_OTHER.ordinal();
+    }
+
+    /**
+     * @return true if this OS belongs to *nix family
+     */
+    public boolean isUnix() {
+        return ordinal() > WINDOWS_OTHER.ordinal() && ordinal() < OS2.ordinal();
+    }
+
+    /**
+     * @param osName name of OS as returned by <code>System.getProperty("os.name")</code>
+     *
+     * @return OS for the specified {@code osName}
+     */
+    public static OS get(String osName) {
+        osName = osName.toLowerCase();
+        for (final OS os : values()) {
+            for (final String name : os.names) {
+                if (osName.contains(name.toLowerCase())) {
+                    return os;
+                }
+            }
+        }
+        throw ContractUtils.unreachable();
+    }
+
+    private static OS current;
+
+    /**
+     * @return OS on which this JVM is running
+     */
+    public static OS get() {
+        if (current == null) {
+            current = get(System.getProperty("os.name"));
+        }
+        return current;
+    }
+}

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

@@ -0,0 +1,18 @@
+<?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>
+        %-5level %logger{36} - %msg%n
+      </Pattern>
+
+    </layout>
+  </appender>
+
+  <root level="WARN">
+    <appender-ref ref="STDOUT" />
+  </root>
+
+</configuration>