1package com.mot.dm.dbtool; 2 3import java.util.*; 4import java.io.*; 5 6public class Generator { 7 8 public static boolean REMOVE_WORKING_DIR = true; 9 public static boolean USE_ZIP = true; 10 public static boolean IS_INPUT_TXT_FILE; 11 public static String ENCODING; // UTF-8 for csv and UTF-16 for txt 12 13 public static String pathMMSFile = null; 14 public static String pathBrowserFile = null; 15 public static String pathJavaAppFile = null; 16 public static String pathIMFile = null; 17 18 public static ArrayList arrMMSLines = new ArrayList(); 19 public static ArrayList arrBrowserLines = new ArrayList(); 20 public static ArrayList arrJavaAppLines = new ArrayList(); 21 public static ArrayList arrIMLines = new ArrayList(); 22 23 //for one combine primary key for all settings 24 public static HashMap hashXmlRecords = new HashMap(); 25 public static Record[] arraySortedRecords; 26 public static StringBuffer operatorsNamesBuffer = new StringBuffer(); 27 public static ByteArray operatorsNamesBytes = new ByteArray(); 28 29 //### tables 30 public static BlockTable operatorsNamesTable; 31 public static BlockTable applicationsSettingsTable; 32 public static BlockTable carrierIndexTable; 33 public static BlockTable headerTable; 34 35 public void proceed() throws Exception { 36 Util.deleteDir(Const.WORKING_DIR); 37 Util.deleteFile(Const.DB_FILE_NAME); 38 Util.deleteFile(Const.ERROR_FILE_NAME); 39 40 if (! (new File(Const.WORKING_DIR)).mkdir()) { 41 throw new Exception( 42 "Error! Cannot create working directory for xml, wbxml and zip files"); 43 } 44 45 fillArrLines(); 46 validateArrLines(); 47 createXmlMessages(); 48 Util.writeRecordsToFiles(); 49 Util.sortAllRecordsIntoArray(); 50 genenerateOperatorsNamesTable(); 51 Arrays.sort(arraySortedRecords); //re-sort again including newlly generated names offset 52 // Util.printRecords(); // for debugging !!!!!!!!!!!!! 53 genenerateApplicationsSettingsTable(); 54 genenerateCarrierIndexTable(); 55 genenerateHeaderTable(); 56 Validator.postValidate(); 57 writeTablesToFile(); 58 59 //clean working directory 60 if (REMOVE_WORKING_DIR) { 61 Util.deleteDir(Const.WORKING_DIR); 62 } 63 64 /// ------------- test -------------- 65 // Util.printRecords(); 66 } 67 68 public void validateArrLines() throws Exception { 69 70 String err = ""; 71 err += Worker.validateAndCreateMMSs(arrMMSLines); 72 err += Worker.validateAndCreateBrowsers(arrBrowserLines); 73 err += Worker.validateAndCreateJavaApps(arrJavaAppLines); 74 err += Worker.validateAndCreateIMs(arrIMLines); 75 76 if (err.length() > 0) { 77 throw new Exception(err); 78 } 79 } 80 81 public void createXmlMessages() throws Exception { 82 Browser.createXmlMessages(); 83 MMS.createXmlMessages(); 84 JavaApp.createXmlMessages(); 85 86 // IM should be last to generate id_name for all other applications!!! 87 // set flag to avoid duplicationNAP names before calling createXmlMessages() 88 // The method setNAPFlagForIMAndValidate() should be changed for new applications 89 Validator.setNAPFlagForIMAndValidate(); 90 IM.createXmlMessages(); 91 } 92 93 public void fillArrLines() throws Exception { 94 if (pathMMSFile != null) { 95 arrMMSLines = Util.readFile(pathMMSFile); 96 } 97 if (pathBrowserFile != null) { 98 arrBrowserLines = Util.readFile(pathBrowserFile); 99 } 100 if (pathJavaAppFile != null) { 101 arrJavaAppLines = Util.readFile(pathJavaAppFile); 102 } 103 if (pathIMFile != null) { 104 arrIMLines = Util.readFile(pathIMFile); 105 } 106 } 107 108 // set offset for Applications Settings for each record and generate Applications Setting Table 109 public void genenerateApplicationsSettingsTable() throws Exception { 110 int totalDataLength = 0; 111 String err = ""; // collected all errors for setBlockApplicationsForOneRecord(); 112 113 // set offset and binary data for Applications Settings for each record 114 for (int i = 0; i < arraySortedRecords.length; i++) { 115 try { 116 arraySortedRecords[i].application_settings_offset = totalDataLength; 117 int currDataLength = setBlockApplicationsForOneRecord( 118 arraySortedRecords[ 119 i]); 120 totalDataLength += currDataLength; 121 } 122 catch (Exception ex) { 123 err += ex.getMessage() + "\n"; 124 } 125 } 126 if (err.length() > 0) { 127 throw new Exception(err); 128 } 129 130 // create appl settings table 131 byte[] b; 132 applicationsSettingsTable = new BlockTable(totalDataLength); 133 for (int i = 0; i < arraySortedRecords.length; i++) { 134 b = arraySortedRecords[i].application_settings; 135 applicationsSettingsTable.appendData(b); 136 arraySortedRecords[i].application_settings = null; // release memory !!!! 137 138 ////////////////-- test --/////////////////// 139 /* int iii = ( ( ( (int) b[0]) & 0xff) << 16) + 140 ( ( ( (int) b[1]) & 0xff) << 8) + ( ( (int) b[2]) & 0xff); 141 System.out.println(arraySortedRecords[i].key.replaceAll(":", "_") + 142 " : " + b.length + " iii= " + (iii >>> 1) + 143 " flag: " + (iii & 1));*/ 144 /////////////////////-- end test-- /////////////////// 145 146 } 147 148 Validator.validateMaxAppsSettingsLength(applicationsSettingsTable.length); 149 int lastOffset = arraySortedRecords[arraySortedRecords.length - 150 1].application_settings_offset; 151 Validator.validateMaxAppsSettingsOffset(lastOffset); 152 } 153 154 // Choose between wbxml or zip (the smallest one) to be used; 155 // adds 3 additional bytes with metadata and set binary data for the record 156 // returns length for the application settings + 3 bytes 157 public int setBlockApplicationsForOneRecord(Record record) throws Exception { 158 String key = record.key; 159 //String generalPath = Const.WORKING_DIR + Const.PATH_SEP + 160 // key.replaceAll(":", "_"); 161 String generalPath = Const.WORKING_DIR + Const.PATH_SEP + 162 Util.generateFileNameFromKey(key); 163 164 File w = new File(generalPath + ".wbxml"); 165 if (!w.exists()) { 166 throw new Exception("Error: The file " + generalPath + 167 ".wbxml doesn't exist!"); 168 } 169 170 FileInputStream in; 171 boolean usedZip; 172 // Choose between wbxml or zip (the smallest one) to be used in case if USE_ZIP 173 // has not been set to false in function main(). 174 if (USE_ZIP) { //zip wbxml files 175 File z = new File(generalPath + ".zip"); 176 if (!z.exists()) { 177 throw new Exception("Error: The file " + generalPath + 178 ".zip doesn't exist!"); 179 } 180 FileInputStream inw = new FileInputStream(w); 181 FileInputStream inz = new FileInputStream(z); 182 usedZip = inz.available() < inw.available(); 183 in = (usedZip) ? inz : inw; 184 } 185 else { // do not zip wbxml files 186 usedZip = false; 187 in = new FileInputStream(w); 188 } 189 190 byte[] appWbxmlSettings = new byte[in.available()]; 191 in.read(appWbxmlSettings); 192 in.close(); 193 194 //get 3 bytes that provide info: for data length (23 bits) and compressed flag (1 bit) 195 //and write it into metaInfo 196 BlockTable metaInfo = new BlockTable( (Const.APP_BLOCK_LENGTH + 197 Const.APP_COMPRESSWD_FLAG) / 8); // 3 bytes 198 int appBlockSettingsLength = metaInfo.data.length + appWbxmlSettings.length; 199 int compressFlag = (usedZip) ? 1 : 0; 200 Util.addBitsToTable(metaInfo, appBlockSettingsLength, 201 Const.APP_BLOCK_LENGTH); 202 Util.addBitsToTable(metaInfo, compressFlag, 203 Const.APP_COMPRESSWD_FLAG); 204 record.setBlockApplicationSettings(metaInfo.data, appWbxmlSettings); 205 206 Validator.validateAppBlockSettingsLength(appBlockSettingsLength, 207 generalPath); 208 209 return appBlockSettingsLength; 210 } 211 212 // generate operators names table with name length. assign offset for each record 213 public static void genenerateOperatorsNamesTable() throws Exception { 214 //operatorsNamesBytes 215 HashMap hashNames = new HashMap(); 216 String name; 217 218 for (int i = 0; i < arraySortedRecords.length; i++) { 219 name = arraySortedRecords[i].operator_name; 220 221 if (hashNames.containsKey(name)) { 222 Integer offset = (Integer) hashNames.get(name); 223 arraySortedRecords[i].operator_name_offset = offset.intValue(); 224 } 225 else { 226 227 byte[] nameByteArr = name.getBytes(); 228 // since operatorsNamesBytes.length are always even... 229 int half_offset = operatorsNamesBytes.length() / 2; 230 Validator.validateOperatorNameOffset(half_offset); //validate half_offset 231 arraySortedRecords[i].operator_name_offset = half_offset; 232 233 int nameLength = nameByteArr.length + 1; //length of name + one byte to present this length. 234 operatorsNamesBytes.addByte( (byte) nameLength); 235 operatorsNamesBytes.addBytes(nameByteArr); 236 if ( (operatorsNamesBytes.length() % 2) > 0) { 237 //add one dummy byte to make it even 238 operatorsNamesBytes.addByte( (byte) 0); 239 } 240 hashNames.put(name, new Integer(half_offset)); 241 } 242 } 243 244 //create operators Names Table 245 operatorsNamesTable = new BlockTable(operatorsNamesBytes.length()); 246 operatorsNamesTable.appendData(operatorsNamesBytes.getBytes()); 247 248 Validator.validateOperatorNamesTableSize(operatorsNamesTable.length); 249 250 } 251 252 /* 253//generate operators names table with name length. assign offset for each record 254 public static void genenerateOperatorsNamesTable() throws Exception { 255 HashMap hashNames = new HashMap(); 256 String name; 257 boolean needAddDummyChar; 258 for (int i = 0; i < arraySortedRecords.length; i++) { 259 needAddDummyChar = false; 260 name = arraySortedRecords[i].operator_name; 261 262 if (hashNames.containsKey(name)) { 263 Integer offset = (Integer) hashNames.get(name); 264 arraySortedRecords[i].operator_name_offset = offset.intValue(); 265 } 266 else { 267 //length of name should be odd since we need to addd one byte which will 268 //present this length. so length of name + one byte will be even. 269 //then offset will be stored as half offset/2 270 271 int half_offset = operatorsNamesBuffer.toString().getBytes(ENCODING).length / 2; 272 arraySortedRecords[i].operator_name_offset = half_offset; 273 int nameLength = name.getBytes(ENCODING).length; 274 if((nameLength % 2) == 0){ 275 //add one dummy char to make it odd 276 needAddDummyChar = true; 277 nameLength++; 278 } 279 // char c = (char) (name.getBytes().length + 1); //length of name + one byte to present this length. 280 char c = (char) (nameLength + 1); //length of name + one byte to present this length. 281 operatorsNamesBuffer.append(c); 282 operatorsNamesBuffer.append(name); 283 if(needAddDummyChar){ 284 operatorsNamesBuffer.append(0); 285 } 286 hashNames.put(name, new Integer(half_offset)); 287 } 288 //validate real offset (half_offset * 2) 289 Validator.validateOperatorNameOffset(arraySortedRecords[i].operator_name_offset * 2); 290 } 291 292 //create operators Names Table 293 operatorsNamesTable = new BlockTable(operatorsNamesBuffer.toString(). 294 getBytes(ENCODING).length); 295 operatorsNamesTable.appendData(operatorsNamesBuffer.toString().getBytes(ENCODING)); 296 297 Validator.validateOperatorNamesTableSize(operatorsNamesTable.length); 298 299 } 300 */ 301 302// generate carrier index table 303 public static void genenerateCarrierIndexTable() throws Exception { 304 //get size for all records and init carrierIndexTable 305 int recordLengthBits = Const.MCC_BITS + Const.MNC_BITS + 306 Const.OPERATOR_NAME_OFFSET_BITS + Const.ACC_TYPE_BITS + 307 Const.APP_AVAIL_BITMAP_BITS + Const.APP_SETTINGS_OFFSET_BITS; 308 int oneRecordLengthBytes = (recordLengthBits + 7) / 8; 309 int tableLengthBytes = oneRecordLengthBytes * arraySortedRecords.length; 310 carrierIndexTable = new BlockTable(tableLengthBytes); 311 312 //write data from each record into arrier index table 313 Record record; 314 for (int i = 0; i < arraySortedRecords.length; i++) { 315 record = arraySortedRecords[i]; 316 int appAvailBitmap = 0; 317 //set mask for available applications 318 if (record.containsBrowser) { 319 appAvailBitmap |= Const.BROWSER_MASK; 320 } 321 if (record.containsIM) { 322 appAvailBitmap |= Const.IM_MASK; 323 } 324 if (record.containsJavaApp) { 325 appAvailBitmap |= Const.JAVA_MASK; 326 } 327 if (record.containsMMS) { 328 appAvailBitmap |= Const.MMS_MASK; 329 } 330 //find value for mnc length: if mns 3 digits it is 1, otherwise - it is 0 331 int mncLengthBitValue = (record.mncLen == 3) ? 1 : 0; 332 333 Util.addBitsToTable(carrierIndexTable, record.mcc, 334 Const.MCC_BITS); 335 Util.addBitsToTable(carrierIndexTable, mncLengthBitValue, 336 Const.MNC_LENGTH_BITS); 337 Util.addBitsToTable(carrierIndexTable, record.mnc, 338 Const.MNC_BITS); 339 Util.addBitsToTable(carrierIndexTable, 340 record.operator_name_offset, 341 Const.OPERATOR_NAME_OFFSET_BITS); 342 Util.addBitsToTable(carrierIndexTable, record.account_type, 343 Const.ACC_TYPE_BITS); 344 Util.addBitsToTable(carrierIndexTable, appAvailBitmap, 345 Const.APP_AVAIL_BITMAP_BITS); 346 Util.addBitsToTable(carrierIndexTable, 347 record.application_settings_offset, 348 Const.APP_SETTINGS_OFFSET_BITS); 349 } 350 } 351 352//### ========== generate Header table ============ ########### 353 public static void genenerateHeaderTable() throws Exception { 354 int tableLengthBytes = ( 355 Const.HEAD_HEAD_SISE + Const.HEAD_OPERATOR_NAMES_TAB_SISE + 356 Const.HEAD_CARRIER_INDEX_TAB_SISE + Const.HEAD_APP_SETTINGS_TAB_SIZE + 357 Const.HEAD_DB_VERSION + 7) / 8; 358 headerTable = new BlockTable(tableLengthBytes); 359 //write header table 360 Util.addBitsToTable(headerTable, tableLengthBytes, 361 Const.HEAD_HEAD_SISE); 362 Util.addBitsToTable(headerTable, operatorsNamesTable.length, 363 Const.HEAD_OPERATOR_NAMES_TAB_SISE); 364 Util.addBitsToTable(headerTable, carrierIndexTable.length, 365 Const.HEAD_CARRIER_INDEX_TAB_SISE); 366 Util.addBitsToTable(headerTable, 367 applicationsSettingsTable.length, 368 Const.HEAD_APP_SETTINGS_TAB_SIZE); 369 Util.addBitsToTable(headerTable, Const.HEAD_DB_VERSION, 370 Const.HEAD_DB_VERSION_TAB_SIZE); 371 } 372 373//### ========== write main DB File and all tables ============ ########### 374 public static void writeTablesToFile() throws Exception { 375 // write sepparate files for the future testing 376 Util.writeFile(Const.WORKING_DIR + Const.PATH_SEP + "header.dat", 377 headerTable.data); 378 Util.writeFile(Const.WORKING_DIR + Const.PATH_SEP + "operators_names.dat", 379 operatorsNamesTable.data); 380 Util.writeFile(Const.WORKING_DIR + Const.PATH_SEP + "app_settings.dat", 381 applicationsSettingsTable.data); 382 Util.writeFile(Const.WORKING_DIR + Const.PATH_SEP + "carrier_index.dat", 383 carrierIndexTable.data); 384 // write main DB file 385 Util.writeDBFile(); 386 } 387 388 public static void main(String[] args) { 389 Const.HEAD_DB_VERSION = 1; 390 391 for (int i = 0; i < args.length; i++) { 392 if ("-mms".equals(args[i]) && args.length > i + 1) { 393 pathMMSFile = args[++i]; 394 if (! (pathMMSFile.endsWith(".txt") || pathMMSFile.endsWith(".csv"))) { 395 System.out.println( 396 "Wrong input file type with MMS setting. Supported types: .txt or .csv"); 397 System.exit(1); 398 } 399 } 400 else if ("-browser".equals(args[i]) && args.length > i + 1) { 401 pathBrowserFile = args[++i]; 402 if (! (pathBrowserFile.endsWith(".txt") || 403 pathBrowserFile.endsWith(".csv"))) { 404 System.out.println( 405 "Wrong input file type with Browser setting. Supported types: .txt or .csv"); 406 System.exit(1); 407 } 408 } 409 else if ("-java".equals(args[i]) && args.length > i + 1) { 410 pathJavaAppFile = args[++i]; 411 if (! (pathJavaAppFile.endsWith(".txt") || 412 pathJavaAppFile.endsWith(".csv"))) { 413 System.out.println( 414 "Wrong input file type with Java setting. Supported types: .txt or .csv"); 415 System.exit(1); 416 } 417 } 418 else if ("-im".equals(args[i]) && args.length > i + 1) { 419 pathIMFile = args[++i]; 420 if (! (pathIMFile.endsWith(".txt") || pathIMFile.endsWith(".csv"))) { 421 System.out.println( 422 "Wrong input file type with IM setting. Supported types: .txt or .csv"); 423 System.exit(1); 424 } 425 } 426 else if ("-nozip".equals(args[i])) { 427 USE_ZIP = false; 428 } 429 else if ("-debug".equals(args[i])) { 430 REMOVE_WORKING_DIR = false; 431 } 432 else if ("-dump".equals(args[i]) && args.length == 2) { 433 DBDumper dbdumper = new DBDumper(); 434 System.out.println("============== Dumping DB File ============== "); 435 dbdumper.dump(args[i + 1]); 436 System.out.println( 437 "============== End dumping DB File ============== \n"); 438 System.exit(0); 439 } 440 else { 441 System.out.println(" Wrong parameters..."); 442 usage(); 443 System.exit(1); 444 } 445 } 446 447 // validate input files and set file type (IS_INPUT_TXT_FILE) 448 String err = Util.validateAndSetInputParms(); 449 if (err != null) { 450 System.out.println(err); 451 usage(); 452 System.exit(1); 453 } 454 455 Generator g = new Generator(); 456 try { 457 g.proceed(); 458 System.out.println( 459 "\n========================================================\n" + 460 "DB generation finished successfully.\n" + 461 "File '" + Const.DB_FILE_NAME + "' has been created.\n" + 462 "========================================================\n"); 463 } 464 catch (Exception e) { 465 Util.deleteFile(Const.DB_FILE_NAME); 466 467 System.out.println( 468 "\n===================== Error ==============================="); 469 System.out.println(" DB generation failed.\n" + 470 " Please check file '" + Const.ERROR_FILE_NAME + 471 "' for more details\n"); 472 //System.out.println(e.getMessage()); 473 System.out.println( 474 "===========================================================\n"); 475 //e.printStackTrace(); 476 try { 477 Util.writeFile(Const.ERROR_FILE_NAME, e.getMessage()); 478 } 479 catch (Exception ex) { 480 ex.printStackTrace(); 481 } 482 } 483 } 484 485 public static void usage() { 486 System.out.println("\n usage:\n" + 487 "java com.mot.dm.dbtool.Generator [-mms <path>] [-browser <path>] [-java <path>] [-im <path>] \n" + 488 "or for test\n" + 489 "java com.mot.dm.dbtool.Generator -dump <path>/" + 490 Const.DB_FILE_NAME 491 ); 492 } 493} 494