PageRenderTime 42ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/src/mpv5/handler/FormatHandler.java

http://mp-rechnungs-und-kundenverwaltung.googlecode.com/
Java | 492 lines | 352 code | 47 blank | 93 comment | 102 complexity | 0e403438357be359f38c6dbd5598f874 MD5 | raw file
Possible License(s): LGPL-3.0, Apache-2.0, GPL-3.0, GPL-2.0, AGPL-3.0, JSON, BSD-3-Clause
  1. /*
  2. * This file is part of YaBS.
  3. *
  4. * YaBS is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * YaBS is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with YaBS. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. package mpv5.handler;
  18. import java.text.MessageFormat;
  19. import java.text.ParsePosition;
  20. import java.util.ArrayList;
  21. import java.util.Arrays;
  22. import java.util.List;
  23. import java.util.Map;
  24. import java.util.concurrent.ConcurrentHashMap;
  25. import mpv5.YabsViewProxy;
  26. import mpv5.db.common.Context;
  27. import mpv5.db.common.DatabaseObject;
  28. import mpv5.db.common.Formattable;
  29. import mpv5.db.common.QueryHandler;
  30. import mpv5.db.common.ReturnValue;
  31. import mpv5.db.objects.*;
  32. import mpv5.globals.Constants;
  33. import mpv5.globals.GlobalSettings;
  34. import mpv5.globals.Messages;
  35. import mpv5.logging.Log;
  36. import mpv5.ui.dialogs.Popup;
  37. import mpv5.usermanagement.MPSecurityManager;
  38. import static mpv5.globals.Constants.*;
  39. /**
  40. *
  41. */
  42. public class FormatHandler {
  43. public static enum TYPES implements MPEnum {
  44. TYPE_BILL(Constants.TYPE_BILL, Messages.TYPE_BILL.getValue()),
  45. TYPE_OFFER(Constants.TYPE_OFFER, Messages.TYPE_OFFER.getValue()),
  46. TYPE_ORDER(Constants.TYPE_ORDER, Messages.TYPE_ORDER.getValue()),
  47. TYPE_CONTACT(Constants.TYPE_CONTACT, Messages.TYPE_CONTACT.getValue()),
  48. TYPE_CUSTOMER(Constants.TYPE_CUSTOMER, Messages.TYPE_CUSTOMER.getValue()),
  49. TYPE_MANUFACTURER(Constants.TYPE_MANUFACTURER, Messages.TYPE_MANUFACTURER.getValue()),
  50. TYPE_SUPPLIER(Constants.TYPE_SUPPLIER, Messages.TYPE_SUPPLIER.getValue()),
  51. TYPE_PRODUCT(Constants.TYPE_PRODUCT, Messages.TYPE_PRODUCT.getValue()),
  52. TYPE_SERVICE(Constants.TYPE_SERVICE, Messages.TYPE_SERVICE.getValue()),
  53. TYPE_REVENUE(Constants.TYPE_REVENUE, Messages.TYPE_REVENUE.getValue()),
  54. TYPE_EXPENSE(Constants.TYPE_EXPENSE, Messages.TYPE_EXPENSE.getValue()),
  55. TYPE_CONVERSATION(Constants.TYPE_CONVERSATION, Messages.TYPE_CONVERSATION.getValue()),
  56. TYPE_ACTIVITY(Constants.TYPE_ACTIVITY, Messages.TYPE_ACTIVITY.getValue()),
  57. TYPE_PRODUCTORDER(Constants.TYPE_PRODUCT_ORDER, Messages.TYPE_PRODUCT_ORDER.getValue()),
  58. TYPE_ORDER_CONFIRMATION(Constants.TYPE_ORDER_CONFIRMATION, Messages.TYPE_CONFIRMATION.getValue()),
  59. TYPE_CONTRACT(Constants.TYPE_CONTRACT, Messages.TYPE_CONTRACT.getValue()),
  60. TYPE_DELIVERY_NOTE(Constants.TYPE_DELIVERY_NOTE, Messages.TYPE_DELIVERY.getValue());
  61. int ids;
  62. String names;
  63. TYPES(int id, String name) {
  64. ids = id;
  65. names = name;
  66. }
  67. @Override
  68. public Integer getId() {
  69. return ids;
  70. }
  71. @Override
  72. public String getName() {
  73. return names;
  74. }
  75. }
  76. public static String INTEGERPART_IDENTIFIER = "{0,number,000000}";
  77. public static String DELETED_IDENTIFIER = "!";
  78. private DatabaseObject source = null;
  79. public static YMessageFormat DEFAULT_FORMAT = new YMessageFormat(INTEGERPART_IDENTIFIER, null);
  80. /**
  81. * This string identifies potential start values from the format string. Use
  82. * as START_VALUE_IDENTIFIERstartvalueSTART_VALUE_IDENTIFIERformat
  83. */
  84. public static String START_VALUE_IDENTIFIER = "@SV@";
  85. /**
  86. * Determines the format type of the given {@link DatabaseObject}
  87. *
  88. * @param obj
  89. * @return An int value representing the format type
  90. */
  91. public synchronized static int determineType(DatabaseObject obj) {
  92. if (obj instanceof Item) {
  93. return ((Item) obj).__getInttype();
  94. } else if (obj instanceof Contact) {
  95. if (((Contact) obj).__getIscustomer()) {
  96. return TYPE_CUSTOMER;
  97. } else if (((Contact) obj).__getIsmanufacturer()) {
  98. return TYPE_MANUFACTURER;
  99. } else if (((Contact) obj).__getIssupplier()) {
  100. return TYPE_SUPPLIER;
  101. } else {
  102. return TYPE_CONTACT;
  103. }
  104. } else if (obj instanceof Product) {
  105. return ((Product) obj).__getInttype();
  106. } else if (obj instanceof Revenue) {
  107. return TYPE_REVENUE;
  108. } else if (obj instanceof Expense) {
  109. return TYPE_EXPENSE;
  110. } else if (obj instanceof Conversation) {
  111. return TYPE_CONVERSATION;
  112. } else if (obj instanceof ActivityList) {
  113. return TYPE_ACTIVITY;
  114. } else if (obj instanceof ProductOrder) {
  115. return TYPE_PRODUCT_ORDER;
  116. }
  117. return -1;
  118. }
  119. /**
  120. *
  121. * @param forObject
  122. */
  123. public FormatHandler(DatabaseObject forObject) {
  124. this.source = forObject;
  125. }
  126. @Override
  127. public String toString() {
  128. return "Format: " + getFormat().format(43) + " for " + source + " (" + determineType(source) + ")";
  129. }
  130. private FormatHandler() {
  131. }
  132. private static Map<String, YMessageFormat> formatCache = null;
  133. /**
  134. *
  135. * @return
  136. */
  137. public synchronized YMessageFormat getFormat() {
  138. int typ = determineType(source);
  139. String key = mpv5.db.objects.User.getCurrentUser().__getIDS() + "@" + typ;
  140. String adminKey = User.ADMIN_ID + "@" + typ;
  141. if (formatCache != null) {
  142. if (!formatCache.containsKey(adminKey) && !formatCache.containsKey(key)) {
  143. Log.Debug(this, "Format caching did not result in a matching format.");
  144. return DEFAULT_FORMAT;
  145. }
  146. if (formatCache.containsKey(key)) {
  147. return formatCache.get(key);
  148. } else {
  149. return formatCache.get(adminKey);
  150. }
  151. }
  152. //Formats not cached yet
  153. formatCache = new ConcurrentHashMap<String, YMessageFormat>();
  154. // c.addAndCondition("usersids", mpv5.db.objects.User.getCurrentUser().__getIDS());
  155. // c.addAndCondition("inttype", determineType(source));
  156. try {
  157. Object[][] formats = QueryHandler.instanceOf().clone(Context.getFormats()).select("cname, ids, inttype, usersids", false);
  158. if (formats.length > 0) {
  159. for (int i = 0; i < formats.length; i++) {
  160. Integer startCount = null;
  161. String value = formats[i][0].toString();
  162. try {
  163. int formatId = Integer.valueOf(formats[i][1].toString());
  164. if (value.startsWith(START_VALUE_IDENTIFIER) && Integer.valueOf(formats[i][2].toString()).intValue() == typ) {
  165. startCount = Integer.valueOf(value.split(START_VALUE_IDENTIFIER)[1]);
  166. value = value.split(START_VALUE_IDENTIFIER)[2];
  167. QueryHandler.instanceOf().clone(Context.getFormats()).update("cname", formatId, value);
  168. Log.Debug(this, "Setting start count to: " + startCount);
  169. }
  170. } catch (Exception numberFormatException) {
  171. Log.Debug(this, numberFormatException);
  172. return DEFAULT_FORMAT;
  173. }
  174. try {
  175. YMessageFormat mFormat = new YMessageFormat(value, startCount);
  176. Log.Debug(this, "Format found: " + mFormat.toPattern() + ", caching for " + formats[i][3].toString() + "@" + formats[i][2].toString());
  177. formatCache.put(formats[i][3].toString() + "@" + formats[i][2].toString(), mFormat);
  178. } catch (Exception e) {
  179. Log.Debug(this, e);
  180. return DEFAULT_FORMAT;
  181. }
  182. }
  183. return getFormat();
  184. } else {
  185. Log.Debug(this, "Format not found, using default format instead!");
  186. return DEFAULT_FORMAT;
  187. }
  188. } catch (Exception ex) {
  189. Log.Debug(ex);
  190. Log.Debug(this, "Format not found, using default format instead!");
  191. return DEFAULT_FORMAT;
  192. }
  193. }
  194. /**
  195. * Contains all formattable Contexts
  196. */
  197. public static List<Context> FORMATTABLE_CONTEXTS = new ArrayList<Context>(Arrays.asList(new Context[]{
  198. Context.getContact(), Context.getCustomer(), Context.getManufacturer(),
  199. Context.getSupplier(), Context.getProduct(), Context.getItem(),
  200. Context.getExpense(), Context.getRevenue(), Context.getOffer(),
  201. Context.getOrder(), Context.getInvoice(), Context.getCompany(),
  202. Context.getActivityList(), Context.getProductOrder()
  203. }));
  204. /**
  205. * Fetches the next number from the database
  206. *
  207. * @param format
  208. * @return
  209. */
  210. public synchronized int getNextNumber(YMessageFormat format) {
  211. if (format.startValue() == null) {
  212. int newN = 0;
  213. DatabaseObject forThis = source;
  214. if (FORMATTABLE_CONTEXTS.contains(forThis.getContext())) {
  215. String query = "";
  216. if (forThis.getContext().equals(Context.getItem())
  217. || forThis.getContext().equals(Context.getInvoice())
  218. || forThis.getContext().equals(Context.getOffer())
  219. || forThis.getContext().equals(Context.getOrder())) {
  220. query = "SELECT cnumber FROM " + forThis.getDbIdentity() + " WHERE ids = (SELECT MAX(ids) from " + forThis.getDbIdentity() + " WHERE inttype ="
  221. + ((Item) forThis).__getInttype() + " and invisible=0)";
  222. } else if (forThis.getContext().equals(Context.getProduct())) {
  223. query = "SELECT cnumber FROM " + forThis.getDbIdentity() + " WHERE ids = (SELECT MAX(ids) from " + forThis.getDbIdentity() + " WHERE inttype ="
  224. + ((Product) forThis).__getInttype() + " and invisible=0)";
  225. } else if (forThis.getContext().equals(Context.getProductOrder())) {
  226. query = "SELECT cnumber FROM " + forThis.getDbIdentity() + " WHERE ids = (SELECT MAX(ids) from " + forThis.getDbIdentity() + " WHERE inttype ="
  227. + ((ProductOrder) forThis).getInttype() + " and invisible=0)";
  228. } else if (forThis.getContext().equals(Context.getContact())
  229. || forThis.getContext().equals(Context.getCompany())
  230. || forThis.getContext().equals(Context.getContactsCompanies())
  231. || forThis.getContext().equals(Context.getCustomer())
  232. || forThis.getContext().equals(Context.getSupplier())
  233. || forThis.getContext().equals(Context.getManufacturer())) {
  234. if (((Contact) forThis).__getIscustomer()) {
  235. query = "SELECT cnumber FROM " + forThis.getDbIdentity() + " WHERE ids = (SELECT MAX(ids) from " + forThis.getDbIdentity() + " WHERE iscustomer = 1 and invisible=0)";
  236. } else if (((Contact) forThis).__getIsmanufacturer()) {
  237. query = "SELECT cnumber FROM " + forThis.getDbIdentity() + " WHERE ids = (SELECT MAX(ids) from " + forThis.getDbIdentity() + " WHERE ismanufacturer = 1 and invisible=0)";
  238. } else if (((Contact) forThis).__getIssupplier()) {
  239. query = "SELECT cnumber FROM " + forThis.getDbIdentity() + " WHERE ids = (SELECT MAX(ids) from " + forThis.getDbIdentity() + " WHERE issupplier = 1 and invisible=0)";
  240. } else {
  241. query = "SELECT cnumber FROM " + forThis.getDbIdentity() + " WHERE ids = (SELECT MAX(ids) from " + forThis.getDbIdentity() + " WHERE issupplier = 0 AND ismanufacturer = 0 AND iscustomer = 0 and invisible=0)";
  242. }
  243. } else {
  244. query = "SELECT cnumber FROM " + forThis.getDbIdentity() + " WHERE ids = (SELECT MAX(ids) from " + forThis.getDbIdentity() + ") and invisible=0";
  245. }
  246. ReturnValue val = QueryHandler.getConnection().freeQuery(
  247. query, MPSecurityManager.VIEW, null);
  248. if (val.hasData()) {
  249. Log.Debug(FormatHandler.class, "Last number found: " + val.getFirstEntry());
  250. try {
  251. newN = ((Formattable) forThis).getFormatHandler().getIntegerPartOf(format, val.getFirstEntry().toString());
  252. } catch (Exception e) {
  253. Log.Debug(e);
  254. }
  255. Log.Debug(FormatHandler.class, "Counter part: " + newN);
  256. return getNextNumber(format, newN);
  257. } else {
  258. Log.Debug(FormatHandler.class, "First entry?: " + newN);
  259. return getNextNumber(format, 0);
  260. }
  261. } else {
  262. throw new UnsupportedOperationException("FormatHandler#getNextNumber is not defined for " + forThis.getContext());
  263. }
  264. } else {
  265. int tmp = format.startValue().intValue();
  266. Log.Debug(FormatHandler.class, "Found Startcount: " + tmp + " for " + format.toPattern());
  267. format.setStartValue(null);
  268. return tmp;
  269. }
  270. }
  271. private synchronized int getNextNumber(final YMessageFormat format, final int lastNumber) {
  272. DatabaseObject forThis = source;
  273. String query = "";
  274. String cnumber = toString(format, lastNumber + 1);
  275. if (forThis.getContext().equals(Context.getItem())
  276. || forThis.getContext().equals(Context.getInvoice())
  277. || forThis.getContext().equals(Context.getOffer())
  278. || forThis.getContext().equals(Context.getOrder())) {
  279. query = "SELECT cnumber FROM " + forThis.getDbIdentity() + " WHERE cnumber = '" + cnumber + "' AND inttype ="
  280. + ((Item) forThis).__getInttype();
  281. } else if (forThis.getContext().equals(Context.getProduct())) {
  282. query = "SELECT cnumber FROM " + forThis.getDbIdentity() + " WHERE cnumber = '" + cnumber + "' AND inttype ="
  283. + ((Product) forThis).__getInttype();
  284. } else if (forThis.getContext().equals(Context.getProductOrder())) {
  285. query = "SELECT cnumber FROM " + forThis.getDbIdentity() + " WHERE cnumber = '" + cnumber + "' AND inttype ="
  286. + ((ProductOrder) forThis).getInttype();
  287. } else if (forThis.getContext().equals(Context.getContact())
  288. || forThis.getContext().equals(Context.getCompany())
  289. || forThis.getContext().equals(Context.getContactsCompanies())
  290. || forThis.getContext().equals(Context.getCustomer())
  291. || forThis.getContext().equals(Context.getSupplier())
  292. || forThis.getContext().equals(Context.getManufacturer())) {
  293. if (((Contact) forThis).__getIscustomer()) {
  294. query = "SELECT cnumber FROM " + forThis.getDbIdentity() + " WHERE cnumber = '" + cnumber + "' AND iscustomer = 1";
  295. } else if (((Contact) forThis).__getIsmanufacturer()) {
  296. query = "SELECT cnumber FROM " + forThis.getDbIdentity() + " WHERE cnumber = '" + cnumber + "' AND ismanufacturer = 1";
  297. } else if (((Contact) forThis).__getIssupplier()) {
  298. query = "SELECT cnumber FROM " + forThis.getDbIdentity() + " WHERE cnumber = '" + cnumber + "' AND issupplier = 1";
  299. } else {
  300. query = "SELECT cnumber FROM " + forThis.getDbIdentity() + " WHERE cnumber = '" + cnumber + "' AND (issupplier = 0 AND ismanufacturer = 0 AND iscustomer = 0)";
  301. }
  302. } else {
  303. query = "SELECT cnumber FROM " + forThis.getDbIdentity() + " WHERE cnumber = '" + cnumber + "'";
  304. }
  305. Log.Debug(FormatHandler.class, "Checking : " + cnumber);
  306. ReturnValue val2 = QueryHandler.getConnection().freeQuery(
  307. query, MPSecurityManager.VIEW, null);
  308. if (val2.hasData()) {
  309. Log.Debug(FormatHandler.class, "Already existing..: " + val2.getData()[0][0]);
  310. return getNextNumber(format, lastNumber + 1);
  311. } else {
  312. int nu = lastNumber + 1;
  313. Log.Debug(FormatHandler.class, "Not existing yet : " + cnumber + ", returning next one: " + nu);
  314. return nu;
  315. }
  316. }
  317. /**
  318. * Formats a given number by the determined number format, <br/>if the {@link setStartCount(Integer)
  319. * } has not been set. Returns the defined start value then.
  320. *
  321. * @param format
  322. * @param number
  323. * @return A formatted number
  324. */
  325. public synchronized String toString(final MessageFormat format, final int number) {
  326. String fs = format.format(new Object[]{number});
  327. Log.Debug(FormatHandler.class, format.toPattern() + " ? " + number + " : " + fs);
  328. String x = VariablesHandler.parse(fs, source);
  329. if (x.length() == 0) {
  330. x = "0000" + number;
  331. }
  332. return x;
  333. }
  334. /**
  335. * Returns the user defined (if defined) String representation of the parent
  336. * object
  337. *
  338. * @return A formatted number
  339. */
  340. public synchronized String toUserString() {
  341. String s = mpv5.db.objects.User.getCurrentUser().getProperties().getProperty("saveformat");
  342. if (s != null && s.length() > 0) {
  343. if (s.contains("/")) {
  344. s = s.substring(s.lastIndexOf("/") + 1);
  345. }
  346. } else {
  347. s = source.toString();
  348. }
  349. return VariablesHandler.parse(s, source);
  350. }
  351. /**
  352. * @return the type
  353. */
  354. public int getType() {
  355. return determineType(source);
  356. }
  357. // /**
  358. // * @param format the format to set
  359. // */
  360. // public void setFormat(MessageFormat format) {
  361. // this.format = format;
  362. // }
  363. //
  364. // /**
  365. // * @param formatPattern the format to set, as String pattern
  366. // */
  367. // public void setFormat(String formatPattern) {
  368. //// Pattern escaper = Pattern.compile("(['{])");
  369. // formatPattern = VariablesHandler.parse(formatPattern, source);
  370. //// formatPattern = escaper.matcher(formatPattern).replaceAll("''$1");
  371. //// Log.Debug(this, formatPattern);
  372. // this.format = new MessageFormat(formatPattern);
  373. // }
  374. /**
  375. *
  376. * @param string
  377. * @return
  378. */
  379. private synchronized int getIntegerPartOf(YMessageFormat format, String string) {
  380. Log.Debug(this, "In getIntegerPartOf " + string + " with " + User.getCurrentUser().getName());
  381. int startindex = 0;
  382. String prop = GlobalSettings.getProperty(format.toPattern() + "_startposition");
  383. Log.Debug(this, "GlobalSettings.getProperty: " + prop + " for " + format.toPattern() + "_startposition");
  384. if (prop != null && !prop.equals("null")) {
  385. try {
  386. startindex = Integer.valueOf(prop);
  387. } catch (NumberFormatException numberFormatException) {
  388. Log.Debug(numberFormatException);
  389. }
  390. }
  391. try {
  392. Number n = null;
  393. YMessageFormat f;
  394. try {
  395. if (startindex < 0) {
  396. Log.Debug(this, " Converting startindex " + startindex + " to " + (string.length() + startindex));
  397. startindex = string.length() + startindex;
  398. }
  399. Log.Debug(this, "Original pattern: " + format.toPattern());
  400. f = new YMessageFormat((VariablesHandler.parse(format.toPattern(), source)).substring(startindex), null);
  401. Log.Debug(this, "Pattern: " + f.toPattern() + " for String: " + string + " Starting at " + startindex);
  402. Object[] result = f.parse(string, new ParsePosition(startindex));
  403. if (result != null) {
  404. n = (Number) result[0];
  405. } else {
  406. Log.Debug(this, "Parsing failed!");
  407. throw new IllegalArgumentException(f.toPattern());
  408. }
  409. } catch (Exception e) {
  410. Log.Debug(this, e);
  411. Popup.error(YabsViewProxy.instance().getIdentifierFrame(), Messages.ERROR_OCCURED + "\n" + "Pattern: " + format.toPattern() + " for String: " + string + " Starting at " + startindex);
  412. }
  413. if (n == null) {
  414. n = 0;
  415. }
  416. return n.intValue();
  417. } catch (Exception ex) {
  418. Log.Debug(ex);
  419. return 0;
  420. }
  421. }
  422. /**
  423. * Returns the next determined number String
  424. *
  425. * @return
  426. */
  427. public synchronized String next() {
  428. YMessageFormat format = getFormat();
  429. return toString(format, getNextNumber(format));
  430. }
  431. public static class YMessageFormat extends java.text.MessageFormat {
  432. private static final long serialVersionUID = 1L;
  433. private Integer startValue = null;
  434. public YMessageFormat(String pattern, Integer startValue) {
  435. super(pattern.replace(DELETED_IDENTIFIER, ""));
  436. this.startValue = startValue;
  437. }
  438. public Integer startValue() {
  439. return startValue;
  440. }
  441. public void setStartValue(Integer val) {
  442. startValue = val;
  443. }
  444. }
  445. }