Subversion Repositories SmartDukaan

Rev

Blame | Last modification | View Log | RSS feed

package com.spice.profitmandi.dao.exception;

import com.spice.profitmandi.common.exception.ProfitMandiBusinessException;
import org.springframework.dao.DataIntegrityViolationException;

import java.sql.DataTruncation;
import java.sql.SQLException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public final class DbErrorTranslator {

        public static final String CODE_TRUNCATION = "DB_TRUNCATION";
        public static final String CODE_DUPLICATE = "DB_DUPLICATE";
        public static final String CODE_FK_VIOLATION = "DB_FK_VIOLATION";
        public static final String CODE_CONSTRAINT = "DB_CONSTRAINT";

        private static final Pattern TRUNCATION_COLUMN = Pattern.compile("Data too long for column '([^']+)'");
        private static final Pattern DUPLICATE_KEY = Pattern.compile("for key '(?:[^.]+\\.)?([^']+)'");
        private static final Pattern FK_COLUMN = Pattern.compile("FOREIGN KEY \\(`([^`]+)`\\)");

        private static final int MYSQL_DUPLICATE_KEY = 1062;
        private static final int MYSQL_FK_NO_REFERENCED = 1452;
        private static final int MYSQL_FK_STILL_REFERENCED = 1451;

        private static final int MAX_CAUSE_DEPTH = 20;

        private DbErrorTranslator() {
        }

        public static ProfitMandiBusinessException translate(DataIntegrityViolationException ex) {
                DataTruncation truncation = findInChain(ex, DataTruncation.class);
                if (truncation != null) {
                        String column = extract(truncation.getMessage(), TRUNCATION_COLUMN);
                        return new ProfitMandiBusinessException(prettifyCamelCase(column), null, CODE_TRUNCATION, ex);
                }

                SQLException sqlEx = findInChain(ex, SQLException.class);
                if (sqlEx != null) {
                        int vendorCode = sqlEx.getErrorCode();
                        String message = sqlEx.getMessage();
                        if (vendorCode == MYSQL_DUPLICATE_KEY) {
                                String key = extract(message, DUPLICATE_KEY);
                                return new ProfitMandiBusinessException(prettifyCamelCase(key), null, CODE_DUPLICATE, ex);
                        }
                        if (vendorCode == MYSQL_FK_NO_REFERENCED || vendorCode == MYSQL_FK_STILL_REFERENCED) {
                                String column = extract(message, FK_COLUMN);
                                return new ProfitMandiBusinessException(prettifyCamelCase(column), null, CODE_FK_VIOLATION, ex);
                        }
                }

                return new ProfitMandiBusinessException(null, null, CODE_CONSTRAINT, ex);
        }

        private static <T extends Throwable> T findInChain(Throwable root, Class<T> type) {
                Throwable cur = root;
                int depth = 0;
                while (cur != null && depth++ < MAX_CAUSE_DEPTH) {
                        if (type.isInstance(cur)) {
                                return type.cast(cur);
                        }
                        Throwable next = cur.getCause();
                        if (next == cur) {
                                break;
                        }
                        cur = next;
                }
                return null;
        }

        private static String extract(String message, Pattern pattern) {
                if (message == null) {
                        return null;
                }
                Matcher m = pattern.matcher(message);
                return m.find() ? m.group(1) : null;
        }

        static String prettifyCamelCase(String raw) {
                if (raw == null || raw.isEmpty()) {
                        return raw;
                }
                String withSpaces = raw.replace('_', ' ');
                StringBuilder spaced = new StringBuilder(withSpaces.length() + 4);
                for (int i = 0; i < withSpaces.length(); i++) {
                        char c = withSpaces.charAt(i);
                        if (i > 0 && Character.isUpperCase(c) && Character.isLowerCase(withSpaces.charAt(i - 1))) {
                                spaced.append(' ');
                        }
                        spaced.append(c);
                }
                String[] parts = spaced.toString().split("\\s+");
                StringBuilder result = new StringBuilder();
                for (String part : parts) {
                        if (part.isEmpty()) {
                                continue;
                        }
                        if (result.length() > 0) {
                                result.append(' ');
                        }
                        result.append(Character.toUpperCase(part.charAt(0)));
                        if (part.length() > 1) {
                                result.append(part.substring(1).toLowerCase());
                        }
                }
                return result.toString();
        }
}