View Javadoc
1   package org.djunits.generator;
2   
3   import java.io.BufferedReader;
4   import java.io.File;
5   import java.io.FileNotFoundException;
6   import java.io.FileReader;
7   import java.io.IOException;
8   import java.io.PrintWriter;
9   import java.net.URISyntaxException;
10  import java.net.URL;
11  import java.nio.file.Files;
12  import java.nio.file.Paths;
13  import java.time.Instant;
14  import java.util.ArrayList;
15  import java.util.HashMap;
16  import java.util.List;
17  import java.util.Map;
18  
19  /**
20   * <p>
21   * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
22   * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>
23   * </p>
24   * @author <a href="https://www.tudelft.nl/averbraeck">Alexander Verbraeck</a>
25   * @author <a href="https://www.tudelft.nl/staff/p.knoppers/">Peter Knoppers</a>
26   */
27  public class GenerateDJUNIT
28  {
29      /** The output folder of the writer -- will be written in Eclipse project-root/generated-code/org/djunits folder. */
30      private static final String generatedCodeRelativePath = "/generated-code/org/djunits/";
31  
32      /** the generation time. */
33      private static String generationTime;
34  
35      /**
36       * The calculated absolute output path (root of the executable or Jar file). In case of an Eclipse run, ../../ is added to
37       * the path to place the results in the root of the project, rather than in target/classes.
38       */
39      private static String absoluteRootPath;
40  
41      /** List of Abs + Rel types. */
42      private static List<String[]> typesAbsRel = new ArrayList<>();
43  
44      /** List of Rel types. */
45      private static List<String> typesRel = new ArrayList<>();
46  
47      /** Map of types to formulas. */
48      private static Map<String, List<String>> formulas = new HashMap<>();
49  
50      /** Map of replacement tags to replacement string. */
51      private static Map<String, String> replaceMap = new HashMap<>();
52  
53      /** Map of replacement tags to type for which the replacement has to be done. */
54      private static Map<String, String> replaceType = new HashMap<>();
55  
56      /**
57       * Read the types from the file /TYPES_ABS_REL.txt.
58       * @throws IOException on I/O error
59       */
60      private static void readAbsRelTypes() throws IOException
61      {
62          URL typesURL = URLResource.getResource("/TYPES_ABS_REL.txt");
63          FileReader fileReader = new FileReader(new File(typesURL.getPath()));
64          BufferedReader bufferedReader = new BufferedReader(fileReader);
65          String line = null;
66          while ((line = bufferedReader.readLine()) != null)
67          {
68              if (line.length() > 0)
69              {
70                  typesAbsRel.add(line.split(","));
71              }
72          }
73          bufferedReader.close();
74      }
75  
76      /**
77       * Read the types from the file /TYPES_REL.txt.
78       * @throws IOException on I/O error
79       */
80      private static void readRelTypes() throws IOException
81      {
82          URL typesURL = URLResource.getResource("/TYPES_REL.txt");
83          FileReader fileReader = new FileReader(new File(typesURL.getPath()));
84          BufferedReader bufferedReader = new BufferedReader(fileReader);
85          String line = null;
86          while ((line = bufferedReader.readLine()) != null)
87          {
88              if (line.length() > 0)
89              {
90                  typesRel.add(line);
91              }
92          }
93          bufferedReader.close();
94      }
95  
96      /**
97       * Read the formulas from the file /FORMULAS.txt.
98       * @throws IOException on I/O error
99       */
100     private static void readFormulas() throws IOException
101     {
102         URL typesURL = URLResource.getResource("/FORMULAS.txt");
103         FileReader fileReader = new FileReader(new File(typesURL.getPath()));
104         BufferedReader bufferedReader = new BufferedReader(fileReader);
105         String type = null;
106         String line = null;
107         List<String> flist = new ArrayList<>();
108         while ((line = bufferedReader.readLine()) != null)
109         {
110             if (line.startsWith("%"))
111             {
112                 if (type != null)
113                 {
114                     formulas.put(type, flist);
115                 }
116                 type = line.replaceAll("%", "").trim();
117                 flist = new ArrayList<>();
118             }
119             else
120             {
121                 if (line.trim().length() > 0)
122                 {
123                     flist.add(line.trim());
124                 }
125             }
126         }
127         formulas.put(type, flist);
128         bufferedReader.close();
129     }
130 
131     /**
132      * Read the replacement strings from the file /REPLACE.txt.
133      * @throws IOException on I/O error
134      */
135     private static void readReplace() throws IOException
136     {
137         URL typesURL = URLResource.getResource("/REPLACE.txt");
138         FileReader fileReader = new FileReader(new File(typesURL.getPath()));
139         BufferedReader bufferedReader = new BufferedReader(fileReader);
140         String tag = null;
141         String line = null;
142         String type = null;
143         String replacementLines = "";
144         while ((line = bufferedReader.readLine()) != null)
145         {
146             if (line.startsWith("##"))
147             {
148                 if (tag != null)
149                 {
150                     replaceMap.put(tag, replacementLines);
151                     replaceType.put(tag, type);
152                     tag = null;
153                 }
154                 else
155                 {
156                     tag = line.trim();
157                     type = bufferedReader.readLine();
158                     replacementLines = "";
159                 }
160             }
161             else
162             {
163                 replacementLines += line + "\n";
164             }
165         }
166         bufferedReader.close();
167     }
168 
169     /****************************************************************************************************************/
170     /********************************************* SCALAR ***********************************************************/
171     /****************************************************************************************************************/
172 
173     /**
174      * Insert formulas based on FORMULAS.txt into the %FORMULAS% marker within the Java file.
175      * @param java String; the java file
176      * @param errorType String; the type for error messaging
177      * @param prefix String; e.g., Float for Float types, or blank for Double types
178      * @return the file with replacements
179      */
180     private static String formulas(String java, String errorType, String prefix)
181     {
182         String ret = java;
183         while (ret.contains("%FORMULAS%"))
184         {
185             int pos = ret.indexOf("%FORMULAS%");
186             ret = ret.replaceFirst("%FORMULAS%", "");
187             int end = ret.indexOf("%", pos);
188             if (end == -1)
189             {
190                 System.err.println("Closing % not found for %FORMULAS% in file for type " + errorType);
191                 return ret;
192             }
193             String type = ret.substring(pos, end);
194             String pType = prefix + type;
195             if (!formulas.containsKey(type))
196             {
197                 System.err.println("Formulas in FORMULAS.txt does not contain entry for type " + errorType);
198                 return ret.substring(0, pos - 1) + ret.substring(pos + type.length() + 2, ret.length() - 1);
199             }
200             String fStr = "";
201             for (String f : formulas.get(type))
202             {
203                 String dm = f.startsWith("/") ? "division" : "multiplication";
204                 String method = f.startsWith("/") ? "divide" : "times";
205                 String mdsign = f.startsWith("/") ? "/" : "*";
206                 f = f.substring(1, f.length());
207                 String param = f.split("=")[0].trim();
208                 String result = f.split("=")[1].trim();
209                 String pParam = prefix + param;
210                 String pResult = prefix + result;
211 
212                 fStr += "        /**\n";
213                 fStr += "         * Calculate the " + dm + " of " + pType + " and " + pParam + ", which results in a ";
214                 fStr += pResult + " scalar.\n";
215                 fStr += "         * @param v " + pType + " scalar\n";
216                 fStr += "         * @return " + pResult + " scalar as a " + dm + " of " + pType + " and " + pParam + "\n";
217                 fStr += "         */\n";
218                 fStr += "        public final " + pResult + " " + method;
219                 fStr += "(final " + pParam + " v)\n";
220                 fStr += "        {\n";
221                 fStr += "            return new " + pResult + "(this.si " + mdsign + " v.si, ";
222                 fStr += result + "Unit.SI);\n";
223                 fStr += "        }\n\n";
224             }
225             ret = ret.substring(0, pos - 1) + fStr + ret.substring(pos + type.length() + 1, ret.length() - 1);
226         }
227         return ret;
228     }
229 
230     /**
231      * Insert replacements based on REPLACCE.txt into the Java file.
232      * @param java String; the file
233      * @param type String; the type
234      * @return the file with replacements
235      */
236     private static String replace(String java, String type)
237     {
238         // replace the "replacement" tags
239         for (String tag : replaceMap.keySet())
240         {
241             String replacement = (replaceType.get(tag).equals(type)) ? replaceMap.get(tag) : "";
242             while (java.contains(tag))
243             {
244                 java = java.replace(tag, replacement);
245             }
246         }
247 
248         // @Generated
249         java = java.replace("@Generated(value = \"GenerateDJUNIT\")",
250                 "@Generated(value = \"" + GenerateDJUNIT.class.getName() + "\", date = \"" + generationTime + "\")");
251 
252         return java;
253     }
254 
255     /**
256      * Replace the %TypeAbs%, %TypeRel%, %TypeAbsUnit%, and %TypeRelUnit% tags in the java string.
257      * @param in String; the original java string
258      * @param type String[]; the types: [abs, rel, unit]
259      * @return the java string with replacements
260      */
261     private static String replaceAbsRel(final String in, final String[] type)
262     {
263         String typeAbs = type[0];
264         String typeRel = type[1];
265         String typeAbsUnit = type[2];
266         String typeRelUnit = type[3];
267         String java = in.replaceAll("%TypeAbs%", typeAbs);
268         java = java.replaceAll("%typeabs%", typeAbs.toLowerCase());
269         java = java.replaceAll("%TYPEABS%", typeAbs.toUpperCase());
270         java = java.replaceAll("%TypeRel%", typeRel);
271         java = java.replaceAll("%typerel%", typeRel.toLowerCase());
272         java = java.replaceAll("%TYPEREL%", typeRel.toUpperCase());
273         java = java.replaceAll("%TypeAbsUnit%", typeAbsUnit);
274         java = java.replaceAll("%typeabsunit%", typeAbsUnit.toLowerCase());
275         java = java.replaceAll("%TYPEABSUNIT%", typeAbsUnit.toUpperCase());
276         java = java.replaceAll("%TypeRelUnit%", typeRelUnit);
277         java = java.replaceAll("%typerelunit%", typeRelUnit.toLowerCase());
278         java = java.replaceAll("%TYPERELUNIT%", typeRelUnit.toUpperCase());
279         return java;
280     }
281 
282     /**
283      * Generate all Abs + Rel classes in value.vdouble.scalar.
284      * @throws IOException on I/O error
285      * @throws URISyntaxException when file could not be found on the file system
286      */
287     private static void generateDoubleScalarAbsRel() throws IOException, URISyntaxException
288     {
289         for (int i = 0; i <= 1; i++)
290         {
291             String relativePath = "value/vdouble/scalar/";
292             URL scalarURL = URLResource
293                     .getResource("/" + relativePath + ((i == 0) ? "DOUBLE_SCALAR_AR_ABS.java" : "DOUBLE_SCALAR_AR_REL.java"));
294             String scalarJava = new String(Files.readAllBytes(Paths.get(scalarURL.toURI())));
295 
296             for (String[] type : typesAbsRel)
297             {
298                 File outPath = new File(absoluteRootPath + relativePath);
299                 outPath.mkdirs();
300                 PrintWriter out = new PrintWriter(absoluteRootPath + relativePath + type[i] + ".java");
301                 String java = new String(scalarJava);
302                 java = replaceAbsRel(java, type);
303                 java = formulas(java, "DoubleScalar => " + type[i], "");
304                 java = replace(java, type[i]);
305                 out.print(java);
306                 out.close();
307                 System.out.println("built: " + absoluteRootPath + relativePath + type[i] + ".java");
308             }
309         }
310     }
311 
312     /**
313      * Generate all Rel classes in value.vdouble.scalar.
314      * @throws IOException on I/O error
315      * @throws URISyntaxException when file could not be found on the file system
316      */
317     private static void generateDoubleScalarRel() throws IOException, URISyntaxException
318     {
319         String relativePath = "value/vdouble/scalar/";
320         URL scalarURL = URLResource.getResource("/" + relativePath + "DOUBLE_SCALAR_REL.java");
321         String scalarJava = new String(Files.readAllBytes(Paths.get(scalarURL.toURI())));
322 
323         for (String type : typesRel)
324         {
325             File outPath = new File(absoluteRootPath + relativePath);
326             outPath.mkdirs();
327             PrintWriter out = new PrintWriter(absoluteRootPath + relativePath + type + ".java");
328             String java = new String(scalarJava);
329             java = java.replaceAll("%Type%", type);
330             java = java.replaceAll("%type%", type.toLowerCase());
331             java = java.replaceAll("%TYPE%", type.toUpperCase());
332             if (java.contains("class Dimensionless"))
333             {
334                 java = java.replace("%DIMLESS%", "implements DimensionlessFunctions<DimensionlessUnit, Dimensionless>");
335                 URL dimlessURL = URLResource.getResource("/" + relativePath + "DimlessFunctions.java");
336                 String dimlessFunctions = new String(Files.readAllBytes(Paths.get(dimlessURL.toURI())));
337                 int pos = java.indexOf("%FORMULAS%");
338                 java = java.substring(0, pos - 1) + dimlessFunctions + java.substring(pos, java.length() - 1);
339             }
340             java = java.replace("%DIMLESS%", "");
341             java = formulas(java, "DoubleScalar => " + type, "");
342             java = replace(java, type);
343             out.print(java);
344             out.close();
345             System.out.println("built: " + absoluteRootPath + relativePath + type + ".java");
346         }
347     }
348 
349     /**
350      * Generate all Abs + Rel classes in value.vfloat.scalar.
351      * @throws IOException on I/O error
352      * @throws URISyntaxException when file could not be found on the file system
353      */
354     private static void generateFloatScalarAbsRel() throws IOException, URISyntaxException
355     {
356         for (int i = 0; i <= 1; i++)
357         {
358             String relativePath = "value/vfloat/scalar/";
359             URL scalarURL = URLResource
360                     .getResource("/" + relativePath + ((i == 0) ? "FLOAT_SCALAR_AR_ABS.java" : "FLOAT_SCALAR_AR_REL.java"));
361             String scalarJava = new String(Files.readAllBytes(Paths.get(scalarURL.toURI())));
362 
363             for (String type[] : typesAbsRel)
364             {
365                 String fType = "Float" + type[i];
366                 File outPath = new File(absoluteRootPath + relativePath);
367                 outPath.mkdirs();
368                 PrintWriter out = new PrintWriter(absoluteRootPath + relativePath + fType + ".java");
369                 String java = new String(scalarJava);
370                 java = replaceAbsRel(java, type);
371                 java = formulas(java, "FloatScalar => " + type[i], "Float");
372                 java = replace(java, type[i]);
373                 out.print(java);
374                 out.close();
375                 System.out.println("built: " + absoluteRootPath + relativePath + fType + ".java");
376             }
377         }
378     }
379 
380     /**
381      * Generate all Rel classes in value.vfloat.scalar.
382      * @throws IOException on I/O error
383      * @throws URISyntaxException when file could not be found on the file system
384      */
385     private static void generateFloatScalarRel() throws IOException, URISyntaxException
386     {
387         String relativePath = "value/vfloat/scalar/";
388         URL scalarURL = URLResource.getResource("/" + relativePath + "FLOAT_SCALAR_REL.java");
389         String scalarJava = new String(Files.readAllBytes(Paths.get(scalarURL.toURI())));
390 
391         for (String type : typesRel)
392         {
393             String fType = "Float" + type;
394             File outPath = new File(absoluteRootPath + relativePath);
395             outPath.mkdirs();
396             PrintWriter out = new PrintWriter(absoluteRootPath + relativePath + fType + ".java");
397             String java = new String(scalarJava);
398             java = java.replaceAll("%Type%", type);
399             java = java.replaceAll("%type%", type.toLowerCase());
400             java = java.replaceAll("%TYPE%", type.toUpperCase());
401             if (java.contains("class FloatDimensionless"))
402             {
403                 java = java.replace("%DIMLESS%", " implements DimensionlessFunctions<DimensionlessUnit, FloatDimensionless>");
404                 URL dimlessURL = URLResource.getResource("/" + relativePath + "DimlessFunctions.java");
405                 String dimlessFunctions = new String(Files.readAllBytes(Paths.get(dimlessURL.toURI())));
406                 int pos = java.indexOf("%FORMULAS%");
407                 java = java.substring(0, pos - 1) + dimlessFunctions + java.substring(pos, java.length() - 1);
408             }
409             java = java.replace("%DIMLESS%", "");
410             java = formulas(java, "FloatScalar => " + type, "Float");
411             java = replace(java, type);
412             out.print(java);
413             out.close();
414             System.out.println("built: " + absoluteRootPath + relativePath + fType + ".java");
415         }
416     }
417 
418     /****************************************************************************************************************/
419     /************************************************ VECTOR ********************************************************/
420     /****************************************************************************************************************/
421 
422     /**
423      * Insert formulas based on FORMULAS.txt into the %FORMULAS% marker within the Java file.
424      * @param java String; the java file
425      * @param errorType String; the type for error messaging
426      * @param prefix String; e.g., Float for Float types, or blank for Double types
427      * @return the file with replacements
428      */
429     private static String formulasVector(String java, String errorType, String prefix)
430     {
431         String ret = java;
432         while (ret.contains("%FORMULAS%"))
433         {
434             int pos = ret.indexOf("%FORMULAS%");
435             ret = ret.replaceFirst("%FORMULAS%", "");
436             int end = ret.indexOf("%", pos);
437             if (end == -1)
438             {
439                 System.err.println("Closing % not found for %FORMULAS% in file for type " + errorType);
440                 return ret;
441             }
442             String type = ret.substring(pos, end);
443             if (!formulas.containsKey(type))
444             {
445                 System.err.println("Formulas in FORMULAS.txt does not contain entry for type " + errorType);
446                 return ret.substring(0, pos - 1) + ret.substring(pos + type.length() + 2, ret.length() - 1);
447             }
448             String fStr = "";
449             ret = ret.substring(0, pos - 1) + fStr + ret.substring(pos + type.length() + 1, ret.length() - 1);
450         }
451         return ret;
452     }
453 
454     /****************************************************************************************************************/
455     /********************************************* DOUBLEVECTOR *****************************************************/
456     /****************************************************************************************************************/
457 
458     /**
459      * Generate all Abs + Rel classes in value.vdouble.vector.
460      * @throws IOException on I/O error
461      * @throws URISyntaxException when file could not be found on the file system
462      */
463     private static void generateDoubleVectorAbsRel() throws IOException, URISyntaxException
464     {
465         for (int i = 0; i <= 1; i++)
466         {
467             String relativePath = "value/vdouble/vector/";
468             URL vectorURL = URLResource
469                     .getResource("/" + relativePath + ((i == 0) ? "DOUBLE_VECTOR_AR_ABS.java" : "DOUBLE_VECTOR_AR_REL.java"));
470             String vectorJava = new String(Files.readAllBytes(Paths.get(vectorURL.toURI())));
471 
472             for (String type[] : typesAbsRel)
473             {
474                 File outPath = new File(absoluteRootPath + relativePath);
475                 outPath.mkdirs();
476                 PrintWriter out = new PrintWriter(absoluteRootPath + relativePath + type[i] + "Vector.java");
477                 String java = new String(vectorJava);
478                 java = replaceAbsRel(java, type);
479                 java = formulasVector(java, "DoubleVector => " + type[i], "");
480                 java = replace(java, type[i]);
481                 out.print(java);
482                 out.close();
483                 System.out.println("built: " + absoluteRootPath + relativePath + type[i] + "Vector.java");
484             }
485         }
486     }
487 
488     /**
489      * Generate all Rel classes in value.vdouble.vector.
490      * @throws IOException on I/O error
491      * @throws URISyntaxException when file could not be found on the file system
492      */
493     private static void generateDoubleVectorRel() throws IOException, URISyntaxException
494     {
495         String relativePath = "value/vdouble/vector/";
496         URL vectorURL = URLResource.getResource("/" + relativePath + "DOUBLE_VECTOR_REL.java");
497         String vectorJava = new String(Files.readAllBytes(Paths.get(vectorURL.toURI())));
498 
499         for (String type : typesRel)
500         {
501             File outPath = new File(absoluteRootPath + relativePath);
502             outPath.mkdirs();
503             PrintWriter out = new PrintWriter(absoluteRootPath + relativePath + type + "Vector.java");
504             String java = new String(vectorJava);
505             java = java.replaceAll("%Type%", type);
506             java = java.replaceAll("%type%", type.toLowerCase());
507             java = java.replaceAll("%TYPE%", type.toUpperCase());
508             if (java.contains("class DimensionlessVector"))
509             {
510                 java = java.replace("%DIMLESS%",
511                         " implements DoubleMathFunctions, DimensionlessFunctions<DimensionlessUnit, DimensionlessVector>");
512                 URL dimlessURL = URLResource.getResource("/" + relativePath + "DimlessFunctions.java");
513                 String dimlessFunctions = new String(Files.readAllBytes(Paths.get(dimlessURL.toURI())));
514                 int pos = java.indexOf("%FORMULAS%");
515                 java = java.substring(0, pos - 1) + dimlessFunctions + java.substring(pos, java.length() - 1);
516             }
517             java = java.replace("%DIMLESS%", "");
518             java = formulasVector(java, "DoubleVector => " + type, "");
519             java = replace(java, type);
520             out.print(java);
521             out.close();
522             System.out.println("built: " + absoluteRootPath + relativePath + type + "Vector.java");
523         }
524     }
525 
526     /****************************************************************************************************************/
527     /********************************************** FLOATVECTOR *****************************************************/
528     /****************************************************************************************************************/
529 
530     /**
531      * Generate all Abs + Rel classes in value.vfloat.vector.
532      * @throws IOException on I/O error
533      * @throws URISyntaxException when file could not be found on the file system
534      */
535     private static void generateFloatVectorAbsRel() throws IOException, URISyntaxException
536     {
537         for (int i = 0; i <= 1; i++)
538         {
539             String relativePath = "value/vfloat/vector/";
540             URL vectorURL = URLResource
541                     .getResource("/" + relativePath + ((i == 0) ? "FLOAT_VECTOR_AR_ABS.java" : "FLOAT_VECTOR_AR_REL.java"));
542             String vectorJava = new String(Files.readAllBytes(Paths.get(vectorURL.toURI())));
543 
544             for (String type[] : typesAbsRel)
545             {
546                 String fType = "Float" + type[i];
547                 File outPath = new File(absoluteRootPath + relativePath);
548                 outPath.mkdirs();
549                 PrintWriter out = new PrintWriter(absoluteRootPath + relativePath + fType + "Vector.java");
550                 String java = new String(vectorJava);
551                 java = replaceAbsRel(java, type);
552                 java = formulasVector(java, "FloatVector => " + fType, "");
553                 java = replace(java, type[i]);
554                 out.print(java);
555                 out.close();
556                 System.out.println("built: " + absoluteRootPath + relativePath + fType + "Vector.java");
557             }
558         }
559     }
560 
561     /**
562      * Generate all Rel classes in value.vfloat.vector.
563      * @throws IOException on I/O error
564      * @throws URISyntaxException when file could not be found on the file system
565      */
566     private static void generateFloatVectorRel() throws IOException, URISyntaxException
567     {
568         String relativePath = "value/vfloat/vector/";
569         URL vectorURL = URLResource.getResource("/" + relativePath + "FLOAT_VECTOR_REL.java");
570         String vectorJava = new String(Files.readAllBytes(Paths.get(vectorURL.toURI())));
571 
572         for (String type : typesRel)
573         {
574             String fType = "Float" + type;
575             File outPath = new File(absoluteRootPath + relativePath);
576             outPath.mkdirs();
577             PrintWriter out = new PrintWriter(absoluteRootPath + relativePath + fType + "Vector.java");
578             String java = new String(vectorJava);
579             java = java.replaceAll("%Type%", type);
580             java = java.replaceAll("%type%", type.toLowerCase());
581             java = java.replaceAll("%TYPE%", type.toUpperCase());
582             if (java.contains("class FloatDimensionlessVector"))
583             {
584                 java = java.replace("%DIMLESS%",
585                         " implements DimensionlessFunctions<DimensionlessUnit, FloatDimensionlessVector>");
586                 URL dimlessURL = URLResource.getResource("/" + relativePath + "DimlessFunctions.java");
587                 String dimlessFunctions = new String(Files.readAllBytes(Paths.get(dimlessURL.toURI())));
588                 int pos = java.indexOf("%FORMULAS%");
589                 java = java.substring(0, pos - 1) + dimlessFunctions + java.substring(pos, java.length() - 1);
590             }
591             java = java.replace("%DIMLESS%", "");
592             java = formulasVector(java, "FloatVector => " + fType, "");
593             java = replace(java, type);
594             out.print(java);
595             out.close();
596             System.out.println("built: " + absoluteRootPath + relativePath + fType + "Vector.java");
597         }
598     }
599 
600     /****************************************************************************************************************/
601     /************************************************ MATRIX ********************************************************/
602     /****************************************************************************************************************/
603 
604     /**
605      * Insert formulas based on FORMULAS.txt into the %FORMULAS% marker within the Java file.
606      * @param java String; the java file
607      * @param errorType String; the type for error messaging
608      * @param prefix String; e.g., Float for Float types, or blank for Double types
609      * @return the file with replacements
610      */
611     private static String formulasMatrix(String java, String errorType, String prefix)
612     {
613         String ret = java;
614         while (ret.contains("%FORMULAS%"))
615         {
616             int pos = ret.indexOf("%FORMULAS%");
617             ret = ret.replaceFirst("%FORMULAS%", "");
618             int end = ret.indexOf("%", pos);
619             if (end == -1)
620             {
621                 System.err.println("Closing % not found for %FORMULAS% in file for type " + errorType);
622                 return ret;
623             }
624             String type = ret.substring(pos, end);
625             if (!formulas.containsKey(type))
626             {
627                 System.err.println("Formulas in FORMULAS.txt does not contain entry for type " + errorType);
628                 return ret.substring(0, pos - 1) + ret.substring(pos + type.length() + 2, ret.length() - 1);
629             }
630             String fStr = "";
631             ret = ret.substring(0, pos - 1) + fStr + ret.substring(pos + type.length() + 1, ret.length() - 1);
632         }
633         return ret;
634     }
635 
636     /****************************************************************************************************************/
637     /********************************************* DOUBLEMATRIX *****************************************************/
638     /****************************************************************************************************************/
639 
640     /**
641      * Generate all Abs + Rel classes in value.vdouble.matrix.
642      * @throws IOException on I/O error
643      * @throws URISyntaxException when file could not be found on the file system
644      */
645     private static void generateDoubleMatrixAbsRel() throws IOException, URISyntaxException
646     {
647         for (int i = 0; i <= 1; i++)
648         {
649             String relativePath = "value/vdouble/matrix/";
650             URL matrixURL = URLResource
651                     .getResource("/" + relativePath + ((i == 0) ? "DOUBLE_MATRIX_AR_ABS.java" : "DOUBLE_MATRIX_AR_REL.java"));
652             String matrixJava = new String(Files.readAllBytes(Paths.get(matrixURL.toURI())));
653 
654             for (String[] type : typesAbsRel)
655             {
656                 File outPath = new File(absoluteRootPath + relativePath);
657                 outPath.mkdirs();
658                 PrintWriter out = new PrintWriter(absoluteRootPath + relativePath + type[i] + "Matrix.java");
659                 String java = new String(matrixJava);
660                 java = replaceAbsRel(java, type);
661                 java = formulasMatrix(java, "DoubleMatrix => " + type[i], "");
662                 java = replace(java, type[i]);
663                 out.print(java);
664                 out.close();
665                 System.out.println("built: " + absoluteRootPath + relativePath + type[i] + "Matrix.java");
666             }
667         }
668     }
669 
670     /**
671      * Generate all Rel classes in value.vdouble.matrix.
672      * @throws IOException on I/O error
673      * @throws URISyntaxException when file could not be found on the file system
674      */
675     private static void generateDoubleMatrixRel() throws IOException, URISyntaxException
676     {
677         String relativePath = "value/vdouble/matrix/";
678         URL matrixURL = URLResource.getResource("/" + relativePath + "DOUBLE_MATRIX_REL.java");
679         String matrixJava = new String(Files.readAllBytes(Paths.get(matrixURL.toURI())));
680 
681         for (String type : typesRel)
682         {
683             File outPath = new File(absoluteRootPath + relativePath);
684             outPath.mkdirs();
685             PrintWriter out = new PrintWriter(absoluteRootPath + relativePath + type + "Matrix.java");
686             String java = new String(matrixJava);
687             java = java.replaceAll("%Type%", type);
688             java = java.replaceAll("%type%", type.toLowerCase());
689             java = java.replaceAll("%TYPE%", type.toUpperCase());
690             if (java.contains("class DimensionlessMatrix"))
691             {
692                 java = java.replace("%DIMLESS%", " implements DimensionlessFunctions<DimensionlessUnit, DimensionlessMatrix>");
693                 URL dimlessURL = URLResource.getResource("/" + relativePath + "DimlessFunctions.java");
694                 String dimlessFunctions = new String(Files.readAllBytes(Paths.get(dimlessURL.toURI())));
695                 int pos = java.indexOf("%FORMULAS%");
696                 java = java.substring(0, pos - 1) + dimlessFunctions + java.substring(pos, java.length() - 1);
697             }
698             java = java.replace("%DIMLESS%", "");
699             java = formulasMatrix(java, "DoubleMatrix => " + type, "");
700             java = replace(java, type);
701             out.print(java);
702             out.close();
703             System.out.println("built: " + absoluteRootPath + relativePath + type + "Matrix.java");
704         }
705     }
706 
707     /****************************************************************************************************************/
708     /********************************************** FLOATMATRIX *****************************************************/
709     /****************************************************************************************************************/
710 
711     /**
712      * Generate all Abs + Rel classes in value.vfloat.matrix.
713      * @throws IOException on I/O error
714      * @throws URISyntaxException when file could not be found on the file system
715      */
716     private static void generateFloatMatrixAbsRel() throws IOException, URISyntaxException
717     {
718         for (int i = 0; i <= 1; i++)
719         {
720             String relativePath = "value/vfloat/matrix/";
721             URL matrixURL = URLResource
722                     .getResource("/" + relativePath + ((i == 0) ? "FLOAT_MATRIX_AR_ABS.java" : "FLOAT_MATRIX_AR_REL.java"));
723             String matrixJava = new String(Files.readAllBytes(Paths.get(matrixURL.toURI())));
724 
725             for (String type[] : typesAbsRel)
726             {
727                 String fType = "Float" + type[i];
728                 File outPath = new File(absoluteRootPath + relativePath);
729                 outPath.mkdirs();
730                 PrintWriter out = new PrintWriter(absoluteRootPath + relativePath + fType + "Matrix.java");
731                 String java = new String(matrixJava);
732                 java = replaceAbsRel(java, type);
733                 java = formulasMatrix(java, "FloatMatrix => " + fType, "");
734                 java = replace(java, type[i]);
735                 out.print(java);
736                 out.close();
737                 System.out.println("built: " + absoluteRootPath + relativePath + fType + "Matrix.java");
738             }
739         }
740     }
741 
742     /**
743      * Generate all Rel classes in value.vfloat.matrix.
744      * @throws IOException on I/O error
745      * @throws URISyntaxException when file could not be found on the file system
746      */
747     private static void generateFloatMatrixRel() throws IOException, URISyntaxException
748     {
749         String relativePath = "value/vfloat/matrix/";
750         URL matrixURL = URLResource.getResource("/" + relativePath + "FLOAT_MATRIX_REL.java");
751         String matrixJava = new String(Files.readAllBytes(Paths.get(matrixURL.toURI())));
752 
753         for (String type : typesRel)
754         {
755             String fType = "Float" + type;
756             File outPath = new File(absoluteRootPath + relativePath);
757             outPath.mkdirs();
758             PrintWriter out = new PrintWriter(absoluteRootPath + relativePath + fType + "Matrix.java");
759             String java = new String(matrixJava);
760             java = java.replaceAll("%Type%", type);
761             java = java.replaceAll("%type%", type.toLowerCase());
762             java = java.replaceAll("%TYPE%", type.toUpperCase());
763             if (java.contains("class FloatDimensionlessMatrix"))
764             {
765                 java = java.replace("%DIMLESS%",
766                         " implements DimensionlessFunctions<DimensionlessUnit, FloatDimensionlessMatrix>");
767                 URL dimlessURL = URLResource.getResource("/" + relativePath + "DimlessFunctions.java");
768                 String dimlessFunctions = new String(Files.readAllBytes(Paths.get(dimlessURL.toURI())));
769                 int pos = java.indexOf("%FORMULAS%");
770                 java = java.substring(0, pos - 1) + dimlessFunctions + java.substring(pos, java.length() - 1);
771             }
772             java = java.replace("%DIMLESS%", "");
773             java = formulasMatrix(java, "FloatMatrix => " + fType, "");
774             java = replace(java, type);
775             out.print(java);
776             out.close();
777             System.out.println("built: " + absoluteRootPath + relativePath + fType + "Matrix.java");
778         }
779     }
780 
781     /****************************************************************************************************************/
782     /********************************************* SISCALAR *********************************************************/
783     /****************************************************************************************************************/
784 
785     /**
786      * Generate SIScalar.java in value.vdouble.scalar.
787      * @throws IOException on I/O error
788      * @throws URISyntaxException when file could not be found on the file system
789      */
790     private static void generateSIScalar() throws IOException, URISyntaxException
791     {
792         String relativePath = "value/vdouble/scalar/";
793         URL siScalarURL = URLResource.getResource("/" + relativePath + "SISCALAR.java");
794         String siJava = new String(Files.readAllBytes(Paths.get(siScalarURL.toURI())));
795         siJava = siJava.replace("@Generated(value = \"GenerateDJUNIT\")",
796                 "@Generated(value = \"" + GenerateDJUNIT.class.getName() + "\", date = \"" + generationTime + "\")");
797         String asJava = new String(
798                 Files.readAllBytes(Paths.get(URLResource.getResource("/" + relativePath + "SISCALAR_AS.java").toURI())));
799 
800         List<String> allRelTypes = new ArrayList<>(typesRel);
801         for (String[] arType : typesAbsRel)
802         {
803             allRelTypes.add(arType[1]);
804         }
805 
806         String asMethods = "";
807         for (String type : allRelTypes)
808         {
809             String lc = type.toLowerCase();
810             asMethods += asJava.replaceAll("%Type%", type).replaceAll("%type%", lc);
811         }
812 
813         File outPath = new File(absoluteRootPath + relativePath);
814         outPath.mkdirs();
815         PrintWriter out = new PrintWriter(absoluteRootPath + relativePath + "SIScalar.java");
816         String java = siJava.replace("%%ASMETHODS%%", asMethods);
817         out.print(java);
818         out.close();
819         System.out.println("built: " + absoluteRootPath + relativePath + "SIScalar.java");
820     }
821 
822     /**
823      * Generate SIScalar.java in value.vfloat.scalar.
824      * @throws IOException on I/O error
825      * @throws URISyntaxException when file could not be found on the file system
826      */
827     private static void generateFloatSIScalar() throws IOException, URISyntaxException
828     {
829         String relativePath = "value/vfloat/scalar/";
830         URL siScalarURL = URLResource.getResource("/" + relativePath + "FLOATSISCALAR.java");
831         String siJava = new String(Files.readAllBytes(Paths.get(siScalarURL.toURI())));
832         siJava = siJava.replace("@Generated(value = \"GenerateDJUNIT\")",
833                 "@Generated(value = \"" + GenerateDJUNIT.class.getName() + "\", date = \"" + generationTime + "\")");
834         String asJava = new String(
835                 Files.readAllBytes(Paths.get(URLResource.getResource("/" + relativePath + "FLOATSISCALAR_AS.java").toURI())));
836 
837         List<String> allRelTypes = new ArrayList<>(typesRel);
838         for (String[] arType : typesAbsRel)
839         {
840             allRelTypes.add(arType[1]);
841         }
842 
843         String asMethods = "";
844         for (String type : allRelTypes)
845         {
846             String lc = type.toLowerCase();
847             asMethods += asJava.replaceAll("%Type%", type).replaceAll("%type%", lc);
848         }
849 
850         File outPath = new File(absoluteRootPath + relativePath);
851         outPath.mkdirs();
852         PrintWriter out = new PrintWriter(absoluteRootPath + relativePath + "FloatSIScalar.java");
853         String java = siJava.replace("%%ASMETHODS%%", asMethods);
854         out.print(java);
855         out.close();
856         System.out.println("built: " + absoluteRootPath + relativePath + "FloatSIScalar.java");
857     }
858 
859     /****************************************************************************************************************/
860     /********************************************* SIVECTOR *********************************************************/
861     /****************************************************************************************************************/
862 
863     /**
864      * Generate SIVector.java in value.vdouble.vector.
865      * @throws IOException on I/O error
866      * @throws URISyntaxException when file could not be found on the file system
867      */
868     private static void generateSIVector() throws IOException, URISyntaxException
869     {
870         String relativePath = "value/vdouble/vector/";
871         URL siVectorURL = URLResource.getResource("/" + relativePath + "SIVECTOR.java");
872         String siJava = new String(Files.readAllBytes(Paths.get(siVectorURL.toURI())));
873         siJava = siJava.replace("@Generated(value = \"GenerateDJUNIT\")",
874                 "@Generated(value = \"" + GenerateDJUNIT.class.getName() + "\", date = \"" + generationTime + "\")");
875         String asJava = new String(
876                 Files.readAllBytes(Paths.get(URLResource.getResource("/" + relativePath + "SIVECTOR_AS.java").toURI())));
877 
878         List<String> allRelTypes = new ArrayList<>(typesRel);
879         for (String[] arType : typesAbsRel)
880         {
881             allRelTypes.add(arType[1]);
882         }
883 
884         String asMethods = "";
885         for (String type : allRelTypes)
886         {
887             String lc = type.toLowerCase();
888             asMethods += asJava.replaceAll("%Type%", type).replaceAll("%type%", lc);
889         }
890 
891         File outPath = new File(absoluteRootPath + relativePath);
892         outPath.mkdirs();
893         PrintWriter out = new PrintWriter(absoluteRootPath + relativePath + "SIVector.java");
894         String java = siJava.replace("%%ASMETHODS%%", asMethods);
895         out.print(java);
896         out.close();
897         System.out.println("built: " + absoluteRootPath + relativePath + "SIVector.java");
898     }
899 
900     /**
901      * Generate SIVector.java in value.vfloat.vector.
902      * @throws IOException on I/O error
903      * @throws URISyntaxException when file could not be found on the file system
904      */
905     private static void generateFloatSIVector() throws IOException, URISyntaxException
906     {
907         String relativePath = "value/vfloat/vector/";
908         URL siVectorURL = URLResource.getResource("/" + relativePath + "FLOATSIVECTOR.java");
909         String siJava = new String(Files.readAllBytes(Paths.get(siVectorURL.toURI())));
910         siJava = siJava.replace("@Generated(value = \"GenerateDJUNIT\")",
911                 "@Generated(value = \"" + GenerateDJUNIT.class.getName() + "\", date = \"" + generationTime + "\")");
912         String asJava = new String(
913                 Files.readAllBytes(Paths.get(URLResource.getResource("/" + relativePath + "FLOATSIVECTOR_AS.java").toURI())));
914 
915         List<String> allRelTypes = new ArrayList<>(typesRel);
916         for (String[] arType : typesAbsRel)
917         {
918             allRelTypes.add(arType[1]);
919         }
920 
921         String asMethods = "";
922         for (String type : allRelTypes)
923         {
924             String lc = type.toLowerCase();
925             asMethods += asJava.replaceAll("%Type%", type).replaceAll("%type%", lc);
926         }
927 
928         File outPath = new File(absoluteRootPath + relativePath);
929         outPath.mkdirs();
930         PrintWriter out = new PrintWriter(absoluteRootPath + relativePath + "FloatSIVector.java");
931         String java = siJava.replace("%%ASMETHODS%%", asMethods);
932         out.print(java);
933         out.close();
934         System.out.println("built: " + absoluteRootPath + relativePath + "FloatSIVector.java");
935     }
936 
937     /****************************************************************************************************************/
938     /********************************************* SIMATRIX *********************************************************/
939     /****************************************************************************************************************/
940 
941     /**
942      * Generate SIMatrix.java in value.vdouble.matrix.
943      * @throws IOException on I/O error
944      * @throws URISyntaxException when file could not be found on the file system
945      */
946     private static void generateSIMatrix() throws IOException, URISyntaxException
947     {
948         String relativePath = "value/vdouble/matrix/";
949         URL siMatrixURL = URLResource.getResource("/" + relativePath + "SIMATRIX.java");
950         String siJava = new String(Files.readAllBytes(Paths.get(siMatrixURL.toURI())));
951         siJava = siJava.replace("@Generated(value = \"GenerateDJUNIT\")",
952                 "@Generated(value = \"" + GenerateDJUNIT.class.getName() + "\", date = \"" + generationTime + "\")");
953         String asJava = new String(
954                 Files.readAllBytes(Paths.get(URLResource.getResource("/" + relativePath + "SIMATRIX_AS.java").toURI())));
955 
956         List<String> allRelTypes = new ArrayList<>(typesRel);
957         for (String[] arType : typesAbsRel)
958         {
959             allRelTypes.add(arType[1]);
960         }
961 
962         String asMethods = "";
963         for (String type : allRelTypes)
964         {
965             String lc = type.toLowerCase();
966             asMethods += asJava.replaceAll("%Type%", type).replaceAll("%type%", lc);
967         }
968 
969         File outPath = new File(absoluteRootPath + relativePath);
970         outPath.mkdirs();
971         PrintWriter out = new PrintWriter(absoluteRootPath + relativePath + "SIMatrix.java");
972         String java = siJava.replace("%%ASMETHODS%%", asMethods);
973         out.print(java);
974         out.close();
975         System.out.println("built: " + absoluteRootPath + relativePath + "SIMatrix.java");
976     }
977 
978     /**
979      * Generate SIMatrix.java in value.vfloat.matrix.
980      * @throws IOException on I/O error
981      * @throws URISyntaxException when file could not be found on the file system
982      */
983     private static void generateFloatSIMatrix() throws IOException, URISyntaxException
984     {
985         String relativePath = "value/vfloat/matrix/";
986         URL siMatrixURL = URLResource.getResource("/" + relativePath + "FLOATSIMATRIX.java");
987         String siJava = new String(Files.readAllBytes(Paths.get(siMatrixURL.toURI())));
988         siJava = siJava.replace("@Generated(value = \"GenerateDJUNIT\")",
989                 "@Generated(value = \"" + GenerateDJUNIT.class.getName() + "\", date = \"" + generationTime + "\")");
990         String asJava = new String(
991                 Files.readAllBytes(Paths.get(URLResource.getResource("/" + relativePath + "FLOATSIMATRIX_AS.java").toURI())));
992 
993         List<String> allRelTypes = new ArrayList<>(typesRel);
994         for (String[] arType : typesAbsRel)
995         {
996             allRelTypes.add(arType[1]);
997         }
998 
999         String asMethods = "";
1000         for (String type : allRelTypes)
1001         {
1002             String lc = type.toLowerCase();
1003             asMethods += asJava.replaceAll("%Type%", type).replaceAll("%type%", lc);
1004         }
1005 
1006         File outPath = new File(absoluteRootPath + relativePath);
1007         outPath.mkdirs();
1008         PrintWriter out = new PrintWriter(absoluteRootPath + relativePath + "FloatSIMatrix.java");
1009         String java = siJava.replace("%%ASMETHODS%%", asMethods);
1010         out.print(java);
1011         out.close();
1012         System.out.println("built: " + absoluteRootPath + relativePath + "FloatSIMatrix.java");
1013     }
1014 
1015     /****************************************************************************************************************/
1016     /********************************************* GENERIC **********************************************************/
1017     /****************************************************************************************************************/
1018 
1019     /**
1020      * Determine calculated absolute output path (root of the executable or Jar file). In case of an Eclipse run, ../../ is
1021      * added to the path to place the results in the root of the project, rather than in target/classes.<br>
1022      * See https://weblogs.java.net/blog/kohsuke/archive/2007/04/how_to_convert.html and
1023      * http://stackoverflow.com/questions/320542/how-to-get-the-path-of-a-running-jar-file and
1024      * http://stackoverflow.com/questions/3153337/get-current-working-directory-in-java
1025      * @throws FileNotFoundException in case file could not be found
1026      */
1027     private static void makeAndCleanAbsolutePath() throws FileNotFoundException
1028     {
1029         URL mainURL = URLResource.getResource("/");
1030         String path;
1031         try
1032         {
1033             path = mainURL.toURI().getPath();
1034         }
1035         catch (URISyntaxException exception)
1036         {
1037             path = mainURL.getPath();
1038         }
1039         if (path.endsWith("/target/classes/"))
1040         {
1041             path = path.substring(0, path.length() - "/target/classes/".length());
1042         }
1043         path += generatedCodeRelativePath;
1044         if (!new File(path).exists())
1045         {
1046             new File(path).mkdirs();
1047         }
1048         else
1049         {
1050             System.out.println("about to delete: " + path);
1051             // if (!deleteRecursive(new File(path)))
1052             // {
1053             // System.err.println("Could not empty directory " + path);
1054             // System.exit(-1);
1055             // }
1056         }
1057         absoluteRootPath = path;
1058         System.out.println("writing into: " + path);
1059     }
1060 
1061     /**
1062      * By default File#delete fails for non-empty directories, it works like "rm". We need something a little more brutal -
1063      * this does the equivalent of "rm -r". From: http://stackoverflow.com/questions/779519/delete-files-recursively-in-java.
1064      * Note: USE CAREFULLY.
1065      * @param path File; Root File Path
1066      * @return true iff the file and all sub files/directories have been removed
1067      * @throws FileNotFoundException on error (e.g., locked file)
1068      */
1069     public static boolean deleteRecursive(File path) throws FileNotFoundException
1070     {
1071         if (!path.exists())
1072         {
1073             throw new FileNotFoundException(path.getAbsolutePath());
1074         }
1075         boolean ret = true;
1076         if (path.isDirectory())
1077         {
1078             for (File f : path.listFiles())
1079             {
1080                 ret = ret && deleteRecursive(f);
1081             }
1082         }
1083         return ret && path.delete();
1084     }
1085 
1086     /**
1087      * @param args String[]; args, should be blank
1088      * @throws IOException on I/O error
1089      * @throws URISyntaxException when file could not be found on the file system
1090      */
1091     public static void main(String[] args) throws IOException, URISyntaxException
1092     {
1093         generationTime = Instant.now().toString();
1094 
1095         makeAndCleanAbsolutePath();
1096         readAbsRelTypes();
1097         readRelTypes();
1098         readFormulas();
1099         readReplace();
1100 
1101         generateDoubleScalarAbsRel();
1102         generateDoubleScalarRel();
1103         generateFloatScalarAbsRel();
1104         generateFloatScalarRel();
1105 
1106         generateDoubleVectorAbsRel();
1107         generateDoubleVectorRel();
1108         generateFloatVectorAbsRel();
1109         generateFloatVectorRel();
1110 
1111         generateDoubleMatrixAbsRel();
1112         generateDoubleMatrixRel();
1113         generateFloatMatrixAbsRel();
1114         generateFloatMatrixRel();
1115 
1116         generateSIScalar();
1117         generateFloatSIScalar();
1118 
1119         generateSIVector();
1120         generateFloatSIVector();
1121 
1122         generateSIMatrix();
1123         generateFloatSIMatrix();
1124     }
1125 
1126 }