최초 커밋

master
xit 2 years ago
commit 83c23f0f7c

@ -0,0 +1,272 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cokr.xit</groupId>
<artifactId>xit-foundation</artifactId>
<version>23.04.01</version>
<packaging>jar</packaging>
<name>xit-foundation</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
<spring.maven.artifact.version>5.3.20</spring.maven.artifact.version>
<org.egovframe.rte.version>4.1.0</org.egovframe.rte.version>
</properties>
<repositories>
<repository>
<id>mvn2s</id>
<url>https://repo1.maven.org/maven2/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>egovframe</id>
<url>http://maven.egovframe.kr:8080/maven/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>egovframe2</id>
<url>https://www.egovframe.go.kr/maven/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.egovframe.rte</groupId>
<artifactId>org.egovframe.rte.fdl.excel</artifactId>
<version>${org.egovframe.rte.version}</version>
</dependency>
<dependency>
<groupId>org.egovframe.rte</groupId>
<artifactId>org.egovframe.rte.ptl.mvc</artifactId>
<version>${org.egovframe.rte.version}</version>
</dependency>
<dependency>
<groupId>org.egovframe.rte</groupId>
<artifactId>org.egovframe.rte.fdl.property</artifactId>
<version>${org.egovframe.rte.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.maven.artifact.version}</version>
<!--
<scope>provided</scope>
-->
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>org.bgee.log4jdbc-log4j2</groupId>
<artifactId>log4jdbc-log4j2-jdbc4.1</artifactId>
<version>1.16</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.9.2</version>
<!--
<scope>test</scope>
-->
</dependency>
<dependency>
<groupId>org.mariadb.jdbc</groupId>
<artifactId>mariadb-java-client</artifactId>
<version>2.7.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<defaultGoal>install</defaultGoal>
<directory>${basedir}/target</directory>
<finalName>${project.artifactId}-${project.version}</finalName>
<resources>
<resource><directory>${basedir}/src/main/resources</directory></resource>
</resources>
<testResources>
<testResource><directory>${basedir}/src/test/resources</directory></testResource>
<testResource><directory>${basedir}/src/main/resources</directory></testResource>
</testResources>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<port>80</port>
<path>/</path>
<systemProperties>
<JAVA_OPTS>-Xms256m -Xmx768m -XX:MaxPermSize=256m</JAVA_OPTS>
</systemProperties>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>hibernate3-maven-plugin</artifactId>
<version>2.1</version>
<configuration>
<components>
<component>
<name>hbm2ddl</name>
<implementation>annotationconfiguration</implementation>
</component>
</components>
</configuration>
<dependencies>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>2.3.2</version>
</dependency>
</dependencies>
</plugin>
<!-- EMMA -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>emma-maven-plugin</artifactId>
<version>1.0-alpha-3</version>
</plugin>
<!-- PMD manven plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<version>3.1</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<includes>
<include>**/*.class</include>
</includes>
</configuration>
</plugin>
<!-- EMMA -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<skipTests>true</skipTests>
<reportFormat>xml</reportFormat>
<excludes>
<exclude>**/Abstract*.java</exclude>
<exclude>**/*Suite.java</exclude>
</excludes>
<includes>
<include>**/*Test.java</include>
</includes>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>emma-maven-plugin</artifactId>
<inherited>true</inherited>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Javadoc -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9.1</version>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,208 @@
package cokr.xit.foundation;
import java.util.function.Supplier;
import javax.annotation.Resource;
import org.egovframe.rte.fdl.property.EgovPropertyService;
import org.springframework.context.MessageSource;
import cokr.xit.foundation.data.Convert;
/** .
* <p>AbstractComponent
* <ul><li>{@link Assert}</li>
* <li>{@link #log() } </li>
* <li>{@link #currentAccess() }</li>
* <li>{@link #currentUser() }</li>
* <li>{@link #properties }</li>
* <li>{@link #message(String, String...) }</li>
* </ul>
* .
* <p>AbstractComponent ' ' + 'Bean' .<br />
* , @Component .<br />
* .
* <pre><code> package cokr.xit.example.business.service.bean;
* {@code @Component("businessBean")}
* public class BusinessBean extends AbstractComponent {
* ...
* }</code></pre>
* <p> @Resource .
* <pre><code> @Resource(name = "businessBean")
* BusinessBean businessBean;</code></pre>
*/
public class AbstractComponent {
/** 프로퍼티 서비스 */
@Resource(name="propertyService")
protected EgovPropertyService properties;
/** 메시지 소스 */
@Resource(name="messageSource")
protected MessageSource messages;
private String logName;
/** .
* @param logName
*/
public void setLogName(String logName) {
this.logName = logName;
}
/** .
* @param <T>
* @return
*/
protected <T extends UserInfo> T currentUser() {
return UserInfo.current();
}
/** .
* @return
*/
protected static Access currentAccess() {
return Access.current();
}
/**lv rv .
* @param lv
* @param rv
* @return
* <ul><li>lv rv true</li>
* <li> false</li>
* </ul>
*/
protected static final boolean equals(Object lv, Object rv) {
return lv == rv ? true : lv != null && lv.equals(rv);
}
/**{@link Assert#isEmpty(Object)}
*/
protected static final boolean isEmpty(Object obj) {
return Assert.isEmpty(obj);
}
/**{@link Assert#ifEmpty(Object, Supplier)} 참고*/
protected static final <T> T ifEmpty(T t, Supplier<T> nt) {
return Assert.ifEmpty(t, nt);
}
/**{@link Assert#ifEmpty(Object, Object)} .
*/
protected static final <T> T ifEmpty(T t, T nt) {
return Assert.ifEmpty(t, nt);
}
/**obj ("") . obj String .
* @param obj
* @return
* <ul><li>obj ("")</li>
* <li> String obj</li>
* </ul>
*/
protected static final String blankIfEmpty(Object obj) {
return ifEmpty((String)obj, "");
}
/**{@link Assert#notEmpty(Object, String)} .
*/
protected static final <T> T notEmpty(T t, String name) {
return Assert.notEmpty(t, name);
}
/**See {@link Convert#toShort(Object)}.*/
protected static final short toShort(Object obj) {
return Convert.toShort(obj);
}
/**See {@link Convert#toInt(Object)}.*/
protected static final int toInt(Object obj) {
return Convert.toInt(obj);
}
/**See {@link Convert#toLong(Object)}.*/
protected static final long toLong(Object obj) {
return Convert.toLong(obj);
}
/**See {@link Convert#toDouble(Object)}.*/
protected static final double toDouble(Object obj) {
return Convert.toDouble(obj);
}
/**See {@link Convert#toFloat(Object)}.*/
protected static final float toFloat(Object obj) {
return Convert.toFloat(obj);
}
/**See {@link Convert#toByte(Object)}.*/
protected static final byte toByte(Object obj) {
return Convert.toByte(obj);
}
/**See {@link Convert#toBoolean(Object)}.*/
protected static final boolean toBoolean(Object obj) {
return Convert.toBoolean(obj);
}
/** key args .
* @param key key
* @param args
* @return
*/
protected String message(String key, String... args) {
return messages.getMessage(key, ifEmpty(args, () -> null), "", currentAccess().getLocale());
}
/**t t .
* t , NullPointerException , message-common 'valueRequired' .
* @param <T>
* @param t
* @param name assertion
* @return t
*/
protected final <T> T required(T t, String name) {
if (!isEmpty(t)) return t;
throw new NullPointerException(message("valueRequired", name));
}
/**{@link Assert#rootCause(Throwable)}
*/
protected static final Throwable rootCause(Throwable t) {
return Assert.rootCause(t);
}
/**{@link ApplicationException#get(Throwable)}
*/
protected static final ApplicationException applicationException(Throwable t) {
return ApplicationException.get(t);
}
/**{@link Assert#runtimeException(Throwable)}
*/
protected static final RuntimeException runtimeException(Throwable t) {
return Assert.runtimeException(t);
}
/**klass Log .
* @param klass Log
* @return Log
*/
protected static Log log(Class<?> klass) {
return Log.get(klass);
}
/** Log .
* @return Log
*/
protected Log log() {
return isEmpty(logName) ? log(getClass()) : Log.get(logName);
}
/** .
* @param <T> AbstractComponent
* @return
*/
@SuppressWarnings("unchecked")
protected <T extends AbstractComponent> T self() {
return (T)this;
}
}

@ -0,0 +1,229 @@
package cokr.xit.foundation;
import java.util.Locale;
/** () .
*/
public class Access extends AbstractComponent {
protected static final ThreadLocal<Access> current = new ThreadLocal<>();
private String
id,
sessionID,
action,
ipAddress;
private boolean
newSession,
mobile,
ajaxRequest,
jsonResponse;
private Locale locale;
private static final String
LOCALHOST_V4 = "127.0.0.1",
LOCALHOST_V6 = "0:0:0:0:0:0:0:1";
/** IP .
* @param address IP
* @param localhost
* @return
* <ul><li> IP </li>
* <li> </li>
* </ul>
*/
public static String getClientAddress(String address, String localhost) {
return LOCALHOST_V4.equals(address) || LOCALHOST_V6.equals(address) ? localhost : address;
}
/** .
* @return
*/
public String getId() {
return ifEmpty(id, id = "access-" + System.currentTimeMillis());
}
/** .
* @return
*/
public String getSessionID() {
return sessionID;
}
/** .
* @param sessionID
* @return Access
*/
public Access setSessionID(String sessionID) {
this.sessionID = sessionID;
return this;
}
/** (: uri url) .
* @return
*/
public String getAction() {
return action;
}
/** (:uri url) .
* @param action
* @return Access
*/
public Access setAction(String action) {
this.action = action;
return this;
}
/** IP .
* @return IP
*/
public String getIpAddress() {
return ipAddress;
}
/** IP .
* @param ipAddress IP
* @return Access
*/
public Access setIpAddress(String ipAddress) {
this.ipAddress = ipAddress;
return this;
}
/** Access .
* @return Access
*/
public static Access current() {
return ifEmpty(current.get(), Access::new);
}
/** Access .
* @return Access
*/
public Access setCurrent() {
current.set(this);
return this;
}
/** Access .
* @return
* <ul><li> true</li>
* <li> false</li>
* </ul>
*/
public boolean inNewSession() {
return newSession;
}
/** Access .
* @param newSession
* <ul><li> true</li>
* <li> false</li>
* </ul>
* @return Access
*/
public Access setNewSession(boolean newSession) {
this.newSession = newSession;
return this;
}
/** .
* @return
* <ul><li> true</li>
* <li> false</li>
* </ul>
*/
public boolean isMobile() {
return mobile;
}
/** .
* @param mobile
* <ul><li> true</li>
* <li> false</li>
* </ul>
* @return Access
*/
public Access setMobile(boolean mobile) {
this.mobile = mobile;
return this;
}
/** AJAX .
* @return
* <ul><li>AJAX true</li>
* <li> false</li>
* </ul>
*/
public boolean isAjaxRequest() {
return ajaxRequest;
}
/** AJAX .
* @param header HTTP 'X-Requested-With'
* @return Access
*/
public Access setAjaxRequest(String header) {
ajaxRequest = "XMLHttpRequest".equalsIgnoreCase(header);
return this;
}
/** JSON .
* @return
* <ul><li>JSON true</li>
* <li> false</li>
* </ul>
*/
public boolean isJsonResponse() {
return jsonResponse;
}
/** JSON .
* @param header HTTP 'accept'
* @return Access
*/
public Access setJsonResponse(String header) {
this.jsonResponse = !isEmpty(header) && header.contains("json");
return this;
}
/** Locale .
* @return Locale
*/
public Locale getLocale() {
return locale != null ? locale : Locale.getDefault();
}
/** Locale .
* @param locale Locale
* @return Access
*/
public Access setLocale(Locale locale) {
this.locale = locale;
return this;
}
/** .
* @return
* <ul><li> true</li>
* <li> false</li>
* </ul>
*/
public boolean isDebug() {
return "true".equals(System.getProperty("debug"));
}
/** Access .
* @return Access
*/
public static Access release() {
Access access = current.get();
current.remove();
return access;
}
@Override
public String toString() {
return String.format("%s(id:'%s', clientIP:'%s', action:'%s')", getClass().getSimpleName(), getId(), getIpAddress(), getAction());
}
}

@ -0,0 +1,146 @@
package cokr.xit.foundation;
import java.net.InetAddress;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/** .
* <ul><li>{@link #getApplicationContext() ApplicationContext}</li>
* <li>{@link #getHostName() }</li>
* <li>{@link #getActiveProfiles() }</li>
* <li>{@link #getStartupDate() }</li>
* </ul>
* @author mjkhan
*/
@Component("applicationContainer")
public class ApplicationContainer implements ApplicationContextAware {
private static ApplicationContainer obj;
public static ApplicationContainer get() {
return obj;
}
private String
hostAddress,
hostName,
canonicalHostName;
private ApplicationContext actx;
private String applicationName;
private List<String> activeProfiles;
private Date startupDate;
private boolean secured;
private ApplicationContainer() {
try {
init();
} catch (Exception e) {
throw ApplicationException.get(e);
}
}
/** IP .
* @return IP
*/
public String getHostAddress() {
return hostAddress;
}
/** .
* @return
*/
public String getHostName() {
return hostName;
}
/**{@link InetAddress#getCanonicalHostName()}
* @return Canonical host name
*/
public String getCanonicalHostName() {
return canonicalHostName;
}
/**ApplicationContainer .
* @throws Exception
*/
protected void init() throws Exception {
InetAddress inetAddress = InetAddress.getLocalHost();
hostAddress = inetAddress.getHostAddress();
hostName = inetAddress.getHostName();
canonicalHostName = inetAddress.getCanonicalHostName();
}
/**ApplicationContext .
* @return ApplicationContext
*/
public ApplicationContext getApplicationContext() {
return actx;
}
private Log log() {
return Log.get(getClass());
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
actx = applicationContext;
applicationName = actx.getApplicationName();
String[] apf = Assert.ifEmpty(actx.getEnvironment().getActiveProfiles(), actx.getEnvironment()::getDefaultProfiles);
activeProfiles = Stream.of(apf).collect(Collectors.toList());
startupDate = new Date(actx.getStartupDate());
secured = actx.containsBean("authorityService");
log().debug("{} loaded", this);
obj = this;
}
/** . 'spring.application.name' .
* @return
*/
public String getApplicationName() {
return applicationName;
}
/** .
* @return
*/
public List<String> getActiveProfiles() {
return activeProfiles;
}
/** .
* @param profiles
* @return
* <ul><li> true</li>
* <li> false</li>
* </ul>
*/
public boolean isProfileActive(String... profiles) {
for (String profile: profiles) {
if (activeProfiles.contains(profile))
return true;
}
return false;
}
public boolean isSecured() {
return secured;
}
/** .
* @return
*/
public Date getStartupDate() {
return startupDate;
}
@Override
public String toString() {
return getClass().getSimpleName() + "[hostAddress=" + hostAddress + ", hostName=" + hostName + ", applicationName=" + applicationName + (secured ? ", secured" : "") + "]";
}
}

@ -0,0 +1,79 @@
package cokr.xit.foundation;
import cokr.xit.foundation.data.DataObject;
/**
* @author mjkhan
*/
public class ApplicationException extends RuntimeException {
private static final long serialVersionUID = 1L;
/** ApplicationException .
* @param cause
* @return ApplicationException
*/
public static ApplicationException get(Throwable cause) {
return cause instanceof ApplicationException ?
ApplicationException.class.cast(cause) :
new ApplicationException(cause);
}
private DataObject objs;
private ApplicationException(Throwable cause) {
super(Assert.rootCause(cause));
}
/** DataObject .
* @return DataObject
*/
public DataObject info() {
if (objs == null)
objs = new DataObject();
return objs;
}
/** .
* @param key
* @param value
* @return ApplicationException
*/
public ApplicationException info(String key, Object value) {
info().set(key, value);
return this;
}
/** .
* @return
*/
public String getCode() {
return objs != null ? objs.string("code") : null;
}
/** .
* @param errorCode
* @return ApplicationException
*/
public ApplicationException setCode(String errorCode) {
return info("code", errorCode);
}
@Override
public String getMessage() {
String msg = objs != null ? objs.string("msg") : "";
if (Assert.isEmpty(msg)) {
Throwable cause = getCause();
if (cause != null)
msg = cause.getMessage();
}
return msg;
}
/** .
* @param msg
* @return ApplicationException
*/
public ApplicationException setMessage(String msg) {
return info("msg", msg);
}
}

@ -0,0 +1,152 @@
package cokr.xit.foundation;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.util.function.Supplier;
/**Assertion
* */
public class Assert {
private Assert() {}
/**obj null, , collection, .
* @param obj
* @return
* <ul><li>obj null, , collection, true</li>
* <li> false</li>
* </ul>
*/
public static final boolean isEmpty(Object obj) {
if (obj == null) return true;
if (obj instanceof String) {
String str = (String)obj;
return str.trim().isEmpty();
}
if (obj instanceof Iterable) {
Iterable<?> objs = (Iterable<?>)obj;
return !objs.iterator().hasNext();
}
if (obj.getClass().isArray()) {
return Array.getLength(obj) < 1;
}
return false;
}
/**t {@link #isEmpty(Object) } nt , t .
* @param <T>
* @param t
* @param nt nt Supplier
* @return
* <ul><li>t t</li>
* <li>t Supplier </li>
* </ul>
*/
public static final <T> T ifEmpty(T t, Supplier<T> nt) {
return !isEmpty(t) ? t : nt != null ? nt.get() : t;
}
/**t {@link #isEmpty(Object) } nt, t .
* @param <T>
* @param t
* @param nt
* @return
* <ul><li>t t</li>
* <li>t nt</li>
* </ul>
*/
public static final <T> T ifEmpty(T t, T nt) {
return ifEmpty(t, () -> nt);
}
/**t t .<br />
* JVM <code>-enableassertion:cokr.xit.Assert</code> <code>-ea:cokr.xit.Assert</code> .<br />
* t {@link #isEmpty(Object) }, NullPointerException .
* @param t
* @param name assertion
* @param <T>
* @return t
*/
public static final <T> T assertNotEmpty(T t, String name) {
try {
assert !isEmpty(t);
return t;
} catch (AssertionError e) {
throw new NullPointerException(name + " 값이 없습니다.");
}
}
/**t t .<br />
* t {@link #isEmpty(Object) }, NullPointerException .
* @param t
* @param name assertion
* @param <T>
* @return t
*/
public static final <T> T notEmpty(T t, String name) {
if (!isEmpty(t)) return t;
throw new NullPointerException(name + " 값이 없습니다.");
}
/**t Throwable .
* @param t Throwable
* @return t Throwable
*/
public static final Throwable rootCause(Throwable t) {
Throwable cause = t != null ? t.getCause() : null;
if (cause == null
&& t instanceof InvocationTargetException)
cause = ((InvocationTargetException)t).getTargetException();
return cause == null || cause == t ? t : rootCause(cause);
}
/**t RuntimeException .
* @param t
* @return RuntimeException
*/
public static final RuntimeException runtimeException(Throwable t) {
t = rootCause(t);
return t instanceof RuntimeException ? RuntimeException.class.cast(t) : new RuntimeException(t);
}
/**{@link Assert} .
* <p> Assert .<br />
* Assert Assert .
* </p>
*/
public static interface Support {
/** {@link Assert#isEmpty(Object)} 참고 */
default boolean isEmpty(Object obj) {
return Assert.isEmpty(obj);
}
/** {@link Assert#ifEmpty(Object, Supplier)} 참고 */
default <T> T ifEmpty(T t, Supplier<T> nt) {
return Assert.ifEmpty(t, nt);
}
/** {@link Assert#ifEmpty(Object, Object)} 참고 */
default <T> T ifEmpty(T t, T nt) {
return Assert.ifEmpty(t, nt);
}
/** {@link Assert#assertNotEmpty(Object, String)} 참고 */
default <T> T assertNotEmpty(T t, String name) {
return Assert.assertNotEmpty(t, name);
}
/** {@link Assert#notEmpty(Object, String)} 참고 */
default <T> T notEmpty(T t, String name) {
return Assert.notEmpty(t, name);
}
/** {@link Assert#rootCause(Throwable)} 참고 */
default Throwable rootCause(Throwable t) {
return Assert.rootCause(t);
}
/** {@link Assert#runtimeException(Throwable)} 참고 */
default RuntimeException runtimeException(Throwable t) {
return runtimeException(t);
}
}
}

@ -0,0 +1,95 @@
package cokr.xit.foundation;
import java.util.HashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**org.slf4j.Logger wrapping .<br />
* slf4j api .
* <p>
* <ul><li> '+' .</li>
* <li> '{}' .</li>
* </ul>
* <pre><code> debug("디버그 내용");
* debug("복잡한 디버그 내용 => {}, {}, {}", "a", "b", "c");</code></pre>
*/
public class Log {
private static final HashMap<Class<?>, Log> byClass = new HashMap<>();
private static final HashMap<String, Log> byName = new HashMap<>();
/**klass Log .
* @param klass
* @return Log
*/
public static final Log get(Class<?> klass) {
Log log = byClass.get(klass);
if (log == null) {
byClass.put(klass, log = new Log(LoggerFactory.getLogger(klass)));
}
return log;
}
/** Log .
* @param logName
* @return Log
*/
public static final Log get(String logName) {
Log log = byName.get(logName);
if (log == null) {
byName.put(logName, log = new Log(LoggerFactory.getLogger(logName)));
}
return log;
}
private Logger logger;
private Log(Logger logger) {
this.logger = logger;
}
/** INFO .
* @param format
* @param args
*/
public void info(String format, Object... args) {
if (logger.isInfoEnabled())
logger.info(format, args);
}
/** WARN .
* @param format
* @param args
*/
public void warn(String format, Object... args) {
if (logger.isWarnEnabled())
logger.warn(format, args);
}
/** DEBUG .
* @param format
* @param args
*/
public void debug(String format, Object... args) {
if (logger.isDebugEnabled())
logger.debug(format, args);
}
/** TRACE .
* @param format
* @param args
*/
public void trace(String format, Object... args) {
if (logger.isTraceEnabled())
logger.trace(format, args);
}
/** ERROR .
* @param format
* @param args
*/
public void error(String format, Object... args) {
if (logger.isErrorEnabled())
logger.error(format, args);
}
}

@ -0,0 +1,89 @@
package cokr.xit.foundation;
import java.io.Serializable;
/** .
*/
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private static final String UNKNOWN = "anonymous";
public static final User unknown = new User().seal();
private String
id,
name,
password;
private boolean sealed;
/**User () .
* @return
* <ul><li> true</li>
* <li> false</li>
* </ul>
*/
public boolean isAuthenticated() {
return !UNKNOWN.equals(getId());
}
/** .
* @return
*/
public String getId() {
return id != null ? id : UNKNOWN;
}
/** .
* @param id
*/
public void setId(String id) {
notSealed().id = id;
}
public String getUsername() {
return getId();
}
/** .
* @return
*/
public String getName() {
return isAuthenticated() ? name : getId();
}
/** .
* @param name
*/
public void setName(String name) {
notSealed().name = name;
}
/** .
* @return
*/
public String getPassword() {
return password;
}
/** .
* @param password
*/
public void setPassword(String password) {
notSealed().password = password;
}
private User seal() {
sealed = true;
return this;
}
private User notSealed() {
if (sealed)
throw new IllegalStateException(this + " is sealed");
return this;
}
@Override
public String toString() {
return String.format("%s('%s', '%s')", getClass().getSimpleName(), getId(), getName());
}
}

@ -0,0 +1,201 @@
package cokr.xit.foundation;
import java.io.Serializable;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.springframework.stereotype.Component;
import cokr.xit.foundation.data.DataObject;
/** .
*/
public class UserInfo implements Serializable {
private static final long serialVersionUID = 1L;
public static final String
NAME = "userInfoProvider",
SEC_NAME = "securedUserInfoProvider";
public static final List<String> ALL_ACTIONS = Stream.of("all-actions").collect(Collectors.toList());
/** .
* @author mjkhan
*/
@Component(NAME)
public static class Provider {
private static Provider obj;
/** Provider .
* @return Provider
*/
public static Provider get() {
if (obj == null) {
ApplicationContainer container = ApplicationContainer.get();
String name = container.isSecured() ? SEC_NAME : NAME;
obj = Provider.class.cast(container.getApplicationContext().getBean(name));
}
return obj;
}
/** 사용자 상세정보 */
protected UserInfo userInfo;
/** .
* @return
*/
public UserInfo currentUser() {
return Assert.ifEmpty(userInfo, () -> userInfo = new UserInfo());
}
/** .
* @param userInfo
*/
public void setUserInfo(UserInfo userInfo) {
this.userInfo = userInfo;
}
}
/** .
* @param <T>
* @return
*/
@SuppressWarnings("unchecked")
public static <T extends UserInfo> T current() {
return (T)Provider.get().currentUser();
}
private User user;
private DataObject info;
/** .
* @return
*/
public User getUser() {
return user != null ? user : User.unknown;
}
/** .
* @param user
*/
public void setUser(User user) {
this.user = user;
}
/** () .
* @return
* <ul><li> true</li>
* <li> false</li>
* </ul>
*/
public boolean isAuthenticated() {
return getUser().isAuthenticated();
}
/** .
* @return
*/
public String getId() {
return getUser().getId();
}
/** .
* @param id
*/
public void setId(String id) {
getUser().setId(id);
}
public String getUsername() {
return getUser().getUsername();
}
/** .
* @return
*/
public String getName() {
return getUser().getName();
}
/** .
* @param name
*/
public void setName(String name) {
getUser().setName(name);
}
/** .
* @return
*/
public String getPassword() {
return getUser().getPassword();
}
/** .
* @param password
*/
public void setPassword(String password) {
getUser().setPassword(password);
}
/** map .
* @return map
*/
public Map<String, Object> getInfo() {
return info != null ? info : Collections.emptyMap();
}
/** key .
* @param key
* @return
*/
@SuppressWarnings("unchecked")
public <T> T info(String key) {
return (T)getInfo().get(key);
}
/** .
* @param key
* @param value
* @return User
*/
public <T extends UserInfo> T setInfo(String key, Object value) {
if (info == null)
info = new DataObject();
info.put(key, value);
return self();
}
/**map .
* map .
* @param map map
* @return User
*/
public <T extends UserInfo> T setInfo(Map<String, ?> map) {
if (map != null)
map.forEach(this::setInfo);
return self();
}
/** url .
* @return url
*/
public List<String> getAccessibleActions() {
return ALL_ACTIONS;
}
/** .
* @param <T>
* @return
*/
@SuppressWarnings("unchecked")
protected <T extends UserInfo> T self() {
return (T)this;
}
@Override
public String toString() {
return String.format("%s('%s', '%s')", getClass().getSimpleName(), getId(), getName());
}
}

@ -0,0 +1,181 @@
package cokr.xit.foundation.component;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import org.egovframe.rte.fdl.property.EgovPropertyService;
import org.egovframe.rte.psl.dataaccess.EgovAbstractMapper;
import org.springframework.context.MessageSource;
import cokr.xit.foundation.Access;
import cokr.xit.foundation.ApplicationException;
import cokr.xit.foundation.Assert;
import cokr.xit.foundation.Log;
import cokr.xit.foundation.UserInfo;
import cokr.xit.foundation.data.DataObject;
/**DAO(Data Access Object) .
* @author mjkhan
*/
public abstract class AbstractDao extends EgovAbstractMapper {
/** 프로퍼티 서비스 */
@Resource(name="propertyService")
protected EgovPropertyService properties;
/** 메시지 소스 */
@Resource(name="messageSource")
protected MessageSource messages;
/** 로그이름 */
private String logName;
/** SQL mapper 네임스페이스 */
private String namespace;
/** .
* @param logName
*/
public void setLogName(String logName) {
this.logName = logName;
}
/**DAO SQL namespace .
* @return DAO SQL namespace
*/
protected String namespace() {
return namespace;
}
/**DAO SQL namespace .
* @param namespace DAO SQL namespace
*/
protected void setNamespace(String namespace) {
this.namespace = namespace;
}
/**DAO SQL ID {@link #namespace()} + '.' + sqlID .
* @param sqlID DAO SQL ID. '.'
* @return {@link #namespace()} + '.' + sqlID
* @see #setNamespace(String)
*/
protected String sqlID(String sqlID) {
if (isEmpty(namespace))
return sqlID;
notEmpty(sqlID, "sqlID");
if (namespace.endsWith(".") || sqlID.startsWith("."))
return namespace + sqlID;
if (sqlID.indexOf(".") > 0)
return sqlID;
return namespace + "." + sqlID;
}
/** .
* @param <T>
* @return
*/
protected <T extends UserInfo> T currentUser() {
return UserInfo.current();
}
/** .
* @return
*/
protected static Access currentAccess() {
return Access.current();
}
/** key args .
* @param key key
* @param args
* @return
*/
protected String message(String key, String... args) {
return messages.getMessage(key, ifEmpty(args, () -> null), currentAccess().getLocale());
}
/**{@link Assert#isEmpty(Object)}
*/
protected static boolean isEmpty(Object obj) {
return Assert.isEmpty(obj);
}
/**{@link Assert#ifEmpty(Object, Supplier)}
*/
protected static <T> T ifEmpty(T t, Supplier<T> nt) {
return Assert.ifEmpty(t, nt);
}
/**obj ("") . obj String .
* @param obj
* @return
* <ul><li>obj ("")</li>
* <li> String obj</li>
* </ul>
*/
protected static final String blankIfEmpty(Object obj) {
return ifEmpty((String)obj, () -> "");
}
/**{@link Assert#notEmpty(Object, String)}
*/
protected static <T> T notEmpty(T t, String s) {
return Assert.notEmpty(t, s);
}
/**{@link ApplicationException#get(Throwable)}
*/
protected static final ApplicationException applicationException(Throwable t) {
return ApplicationException.get(t);
}
protected static <T extends List<Map<String, Object>>> T underscoredToCamelCase(T list) {
if (list.isEmpty())
return list;
Set<Map.Entry<String, String>> keymap = list.get(0).keySet().stream().collect(
Collectors.toMap(k -> k, v -> camelCase(v), (k1, k2) -> k1, LinkedHashMap::new)
).entrySet();
list.forEach(row ->
keymap.forEach(entry -> row.put(entry.getValue(), row.remove(entry.getKey())))
);
return list;
}
private static String camelCase(String str) {
StringBuilder buf = new StringBuilder();
for (String token: str.split("_")) {
if (buf.length() < 1)
buf.append(token.toLowerCase());
else
buf.append(token.substring(0, 1).toUpperCase() + token.substring(1).toLowerCase());
}
return buf.toString();
}
/** DataObject .
* @return DataObject
*/
protected DataObject params() {
return new DataObject();
}
/**klass Log .
* @param klass
* @return Log
*/
protected static Log log(Class<?> klass) {
return Log.get(klass);
}
/** Log .
* @return Log
*/
protected Log log() {
return isEmpty(logName) ? log(getClass()) : Log.get(logName);
}
}

@ -0,0 +1,101 @@
package cokr.xit.foundation.component;
import cokr.xit.foundation.UserInfo;
import cokr.xit.foundation.data.DataObject;
/** .<br />
* ,<br />
* ( || ) + 'Mapper' .
* {@code @Mapper} . .
* <pre><code> package cokr.xit.example.business.dao;
* import org.egovframe.rte.psl.dataaccess.mapper.Mapper;
* {@code @Mapper("tableBMapper")}
* public interface TableBMapper extends AbstractMapper {
* ...
* }</code></pre>
* <p><b> </b><br />
* SQL .
* <ul><li> , Mapper -mapper .<br />
* ) TableBMapper interface -> tableB-mapper.xml</li>
* <li> (fully-qualified name) </li>
* <li>parameterType, resultType ,<br />
* alias </li>
* <li>SQL </li>
* <li>SQL .<br />
* <pre>{@code .()
* ) tableBMapper.selectTableBList( )
* }</pre>
* </li>
* </ul>
* <p><b>SELECT</b><br />
* <ul><li> * , .</li>
* <li> .</li>
* <li>INNER JOIN , .</li>
* <li>SELECT SELECT .</li>
* </ul>
* <pre>{@code <select id="selectTableBList" parameterType="map" resultType="map">
* SELECT A.ID
* , A.NAME
* , A.PHONE_NO
* , B.CITY
* , C.DONG
* FROM TBL_TABLE_A A
* , TBL_TABLE_B B
* LEFT OUTER JOIN TBL_TABLE_C C ON B.ADDR_ID = C.ADDR_ID
* WHERE ID = #{id}
* AND B.JUSO_CODE = #{jusoCode}
* AND A.ID = B.ID
* ORDER BY A.ID
* <select>}</pre>
* <p><b>INSERT</b><br />
* INSERT INSERT
* <pre>{@code <insert id="insertTableB" parameterType="cokr.xit.example.business.Entity">
* INSERT INTO TBL_TABLE_B (
* ID
* , NAME
* , PHONE_NO
* , ...
* ) VALUES (
* #{id}
* , #{name}
* , #{phoneNo}
* , ...
* )
* <insert>}</pre>
* <p><b>UPDATE</b><br />
* UPDATE UPDATE
* <pre>{@code <update id="updateTableB" parameterType="cokr.xit.example.business.Entity">
* UPDATE TBL_TABLE_B
* SET NAME = #{name}
* , PHONE_NO = #{phoneNo}
* , ...
* WHERE ID = #{id}
* <update>}</pre>
* <p><b>DELETE</b><br />
* DELETE DELETE
* <pre>{@code <delete id="updateTableB" parameterType="cokr.xit.example.business.Entity">
* DELETE FROM TBL_TABLE_B
* WHERE ID = #{id}
* <delete>}</pre>
* @author mjkhan
*/
public interface AbstractMapper extends
cokr.xit.foundation.Assert.Support,
cokr.xit.foundation.data.Convert.Support {
/** .
* @return
*/
default UserInfo currentUser() {
return UserInfo.current();
}
/** DataObject .
* "currentUser" .
* @return DataObject
*/
default DataObject params() {
return new DataObject()
.set("currentUser", currentUser());
}
}

@ -0,0 +1,157 @@
package cokr.xit.foundation.component;
import java.util.function.Supplier;
import javax.annotation.Resource;
import org.egovframe.rte.fdl.cmmn.EgovAbstractServiceImpl;
import org.egovframe.rte.fdl.property.EgovPropertyService;
import org.springframework.context.MessageSource;
import cokr.xit.foundation.Access;
import cokr.xit.foundation.ApplicationException;
import cokr.xit.foundation.Assert;
import cokr.xit.foundation.Log;
import cokr.xit.foundation.UserInfo;
/**
* <p> .<br />
* , .
* <p> , ' ' + 'ServiceBean' .<br />
* @Service , .
* .
* <pre><code> package cokr.xit.example.business.service.bean;
* ...
* {@code @Service("businessService")}
* public class BusinessServiceBean extends AbstractServiceBean implements BusinessService {
* ...
* }</code></pre>
* @Resource .
* <pre><code> @Resource(name = "businessService")
* BusinessService businessService;</code></pre>
* @author mjkhan
*/
public abstract class AbstractServiceBean extends EgovAbstractServiceImpl {
/** 프로퍼티 서비스 */
@Resource(name="propertyService")
protected EgovPropertyService properties;
/** 메시지 소스 */
@Resource(name="messageSource")
protected MessageSource messages;
/** 로그이름 */
private String logName;
/** .
* @param logName
*/
public void setLogName(String logName) {
this.logName = logName;
}
/** .
* @return
*/
protected <T extends UserInfo> T currentUser() {
return UserInfo.current();
}
/** .
* @return
*/
protected static Access currentAccess() {
return Access.current();
}
/** key args .
* @param key key
* @param args
* @return
*/
protected String message(String key, String... args) {
return messages.getMessage(key, ifEmpty(args, () -> null), currentAccess().getLocale());
}
/**lv rv .
* @param lv
* @param rv
* @return
* <ul><li>lv rv true</li>
* <li> false</li>
* </ul>
*/
protected static final boolean equals(Object lv, Object rv) {
return lv == rv ? true : lv != null && lv.equals(rv);
}
/**{@link Assert#isEmpty(Object)}
*/
protected static final boolean isEmpty(Object obj) {
return Assert.isEmpty(obj);
}
/**{@link Assert#ifEmpty(Object, Supplier)} 참고*/
protected static final <T> T ifEmpty(T t, Supplier<T> nt) {
return Assert.ifEmpty(t, nt);
}
/**{@link Assert#ifEmpty(Object, Object)} .
*/
protected static final <T> T ifEmpty(T t, T nt) {
return Assert.ifEmpty(t, nt);
}
/**obj ("") . obj String .
* @param obj
* @return
* <ul><li>obj ("")</li>
* <li> String obj</li>
* </ul>
*/
protected static final String blankIfEmpty(Object obj) {
return ifEmpty((String)obj, () -> "");
}
/**{@link Assert#notEmpty(Object, String)} .
*/
protected static final <T> T notEmpty(T t, String name) {
return Assert.notEmpty(t, name);
}
/**t t .
* t , NullPointerException , message-common 'valueRequired' .
* @param t
* @param name assertion
* @return t
*/
protected final <T> T required(T t, String name) {
if (!isEmpty(t)) return t;
throw new NullPointerException(message("valueRequired", name));
}
/**{@link Assert#rootCause(Throwable)}
*/
protected static final Throwable rootCause(Throwable t) {
return Assert.rootCause(t);
}
/**{@link ApplicationException#get(Throwable)}
*/
protected static final ApplicationException applicationException(Throwable t) {
return ApplicationException.get(t);
}
/**klass Log .
* @param klass
* @return Log
*/
protected static Log log(Class<?> klass) {
return Log.get(klass);
}
/** Log .
* @return Log
*/
protected Log log() {
return isEmpty(logName) ? log(getClass()) : Log.get(logName);
}
}

@ -0,0 +1,120 @@
package cokr.xit.foundation.component;
/** .
* <p>pageNum, fetchSize
* <ul><li>0 .</li>
* <li> .</li>
* </ul>
* @author mjkhan
*/
public class QueryRequest extends ServiceRequest {
private static final long serialVersionUID = 1L;
private String by;
private String term;
private String orderBy;
private int pageNum;
private int fetchSize;
private String download;
/** .
* @return
*/
public String getBy() {
return ifEmpty(by, () -> null);
}
/** .
* @param by
* @return QueryRequest
*/
public <T extends QueryRequest> T setBy(String by) {
this.by = by;
return self();
}
/** .
* @return
*/
public String getTerm() {
return ifEmpty(term, () -> null);
}
/** .
* @param term
* @return QueryRequest
*/
public <T extends QueryRequest> T setTerm(String term) {
this.term = term;
return self();
}
/** .
* @return
*/
public String getOrderBy() {
return orderBy;
}
/** .
* @param orderBy
* @return QueryRequest
*/
public <T extends QueryRequest> T setOrderBy(String orderBy) {
this.orderBy = orderBy;
return self();
}
/** .
* @return dataStart
*/
public int getPageNum() {
return isEmpty(download) ? pageNum : 0;
}
/** .
* @param pageNum
* @return QueryRequest
*/
public <T extends QueryRequest> T setPageNum(int pageNum) {
this.pageNum = pageNum;
return self();
}
/** .
* @return fetchSize
*/
public int getFetchSize() {
return isEmpty(download) ? fetchSize : 0;
}
/** .
* @param fetchSize
* @return QueryRequest
*/
public <T extends QueryRequest> T setFetchSize(int fetchSize) {
this.fetchSize = fetchSize;
return self();
}
/** .
* @return download
* <ul><li> - "xls"</li>
* <li> </li>
* </ul>
*/
public String getDownload() {
return download;
}
/** .
* @param download
* <ul><li> - "xls"</li>
* <li> </li>
* </ul>
* @return QueryRequest
*/
public <T extends QueryRequest> T setDownload(String download) {
this.download = download;
return self();
}
}

@ -0,0 +1,52 @@
package cokr.xit.foundation.component;
import java.io.Serializable;
import cokr.xit.foundation.AbstractComponent;
/** .<br />
* (4 ) .<br />
* .
* @author mjkhan
*/
public abstract class ServiceRequest extends AbstractComponent implements Serializable {
private static final long serialVersionUID = 1L;
private String type;
/** . .
* @return
*/
protected String getType() {
return ifEmpty(type, "");
}
/** . .
* @param type
* @return
*/
protected <T extends ServiceRequest> T setType(String type) {
this.type = type;
return self();
}
/** .<br />
* RuntimeException .
*/
public void validate() {}
/** .
* @return
* <ul><li> true</li>
* <li> false</li>
* </ul>
*/
public boolean isValid() {
try {
validate();
return true;
} catch (Exception e) {
return false;
}
}
}

@ -0,0 +1,14 @@
package cokr.xit.foundation.component;
import java.io.Serializable;
import cokr.xit.foundation.AbstractComponent;
/** .<br />
* .<br />
* .
* @author mjkhan
*/
public abstract class ServiceResponse extends AbstractComponent implements Serializable {
private static final long serialVersionUID = 1L;
}

@ -0,0 +1,3 @@
/** .
*/
package cokr.xit.foundation.component;

@ -0,0 +1,190 @@
package cokr.xit.foundation.data;
import java.nio.charset.Charset;
import java.util.Arrays;
import cokr.xit.foundation.AbstractComponent;
/** charset `
* <p> euc-kr .
* <pre><code> String str = "뿌리 깊은 나무는 바람에 아니...";
* BSTR euc_kr = new BSTR("euc-kr").set(str);
* String converted = euc_kr.string();
* </code></pre>
*
* <p> 24 .
* <pre><code> String str24 = euc_kr.string(24);
* </code></pre>
*
* <p> 25 10 .
* <pre><code> String substr = euc_kr.string(25, 10);
* </code></pre>
*
* <p> 36 54 .
* <pre><code> substr = euc_kr.substring(36, 54);
* </code></pre>
*
* @author mjkhan
*/
public class BSTR extends AbstractComponent {
private static final byte[] EMPTY = new byte[0];
private Charset charset;
private byte[] bytes;
private String str;
private StringBuilder buff;
/** BSTR .
* @param charset
*/
public BSTR(Charset charset) {
this.charset = ifEmpty(charset, Charset::defaultCharset);
}
/** BSTR .
* @param charset
*/
public BSTR(String charset) {
this(charset != null ? Charset.forName(charset) : null);
}
/** . {@link #BSTR(Charset) } .
* @param obj
* @return BSTR
*/
public BSTR set(Object obj) {
String s = obj != null ? obj.toString() : null;
return set(s != null ? s.getBytes(charset) : null);
}
/** .
* @param bytes
* @return BSTR
*/
public BSTR set(byte[] bytes) {
this.bytes = bytes != null ? bytes : EMPTY;
str = null;
return initBuffer();
}
private BSTR initBuffer() {
if (buff == null)
buff = new StringBuilder();
else
buff.delete(0, buff.length());
return this;
}
/** .
* @return
*/
public long byteLength() {
return bytes.length;
}
/** .
* @return
* <ul><li> true</li>
* <li> false</li>
* </ul>
*/
public boolean isEmpty() {
return byteLength() < 1;
}
/** .
* @return
*/
public String string() {
return ifEmpty(str, () -> str = new String(bytes, charset));
}
/** .
* @param byteLength
* @return
*/
public String string(int byteLength) {
long diff = byteLength - byteLength();
if (diff > 0) {
initBuffer();
buff.append(string());
for (long i = 0; i < diff; ++i)
buff.append(' ');
return buff.toString();
}
if (diff < 0)
return substring(0, byteLength);
return string();
}
/** .
* @param beginIndex (0 )
* @param byteLength
* @return
*/
public String string(int beginIndex, int byteLength) {
return substring(beginIndex, beginIndex + byteLength);
}
/** .
* @param beginIndex
* @param endIndex
* @return
*/
public String substring(int beginIndex, int endIndex) {
if (endIndex > byteLength())
throw new IndexOutOfBoundsException(String.format("beginIndex: %d, endIndex:%d", beginIndex, endIndex));
int size = 0;
int length = endIndex - beginIndex;
initBuffer();
byte[] copy = Arrays.copyOfRange(bytes, beginIndex, endIndex);
for (char ch: new String(copy, charset).toCharArray()) {
int s = String.valueOf(ch).getBytes(charset).length;
if ((size + s) > length) break;
size += s;
buff.append(readable(ch) ? ch : ' ');
}
for (int i = 0, diff = length - size; i < diff; ++i)
buff.append(' ');
return buff.toString();
}
private static boolean readable(char ch) {
if (Character.isLetterOrDigit(ch))
return true;
int type = Character.getType(ch);
return type >= Character.DASH_PUNCTUATION && type <= Character.MODIFIER_SYMBOL;
}
/** .
* @param length
* @return
*/
public String number(int length) {
String num = string().replace(" ", "0");
int diff = length - num.length();
if (diff > 0) {
initBuffer();
for (long i = 0; i < diff; ++i)
buff.append(num);
return buff.toString();
}
if (diff < 0)
return num.substring(0, length);
return num;
}
@Override
public String toString() {
return string();
}
}

@ -0,0 +1,279 @@
package cokr.xit.foundation.data;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.HashMap;
import cokr.xit.foundation.Assert;
/**
*/
public class Convert {
private Convert() {}
/** .
* @param klass
* @param s
* @return
*/
public static final Object toObject(Class<?> klass, String s) {
if (Assert.isEmpty(s)) return null;
if (String.class.equals(Assert.notEmpty(klass, "klass"))) return s;
s = s.trim();
if (isNumber(klass)) {
s = s.replace(",", "");
if (BigDecimal.class.equals(klass)) return new BigDecimal(s);
else if (Double.class.equals(klass)) return Double.valueOf(s);
else if (Float.class.equals(klass)) return Float.valueOf(s);
else if (BigInteger.class.equals(klass)) return new BigInteger(s);
else if (Integer.class.equals(klass)) return Integer.valueOf(s);
else if (Long.class.equals(klass)) return Long.valueOf(s);
else if (Short.class.equals(klass)) return Short.valueOf(s);
else if (Byte.class.equals(klass)) return Byte.valueOf(s);
} else {
if (Boolean.class.equals(klass)) return Boolean.valueOf(s);
else if (Character.class.equals(klass)) return Character.valueOf(s.charAt(0));
/*
if (Clob.class.isAssignableFrom(klass)) return s;
else if (Date.class.equals(klass)) return Date.valueOf(s);
else if (Time.class.equals(klass)) return Time.valueOf(s);
else if (Timestamp.class.equals(klass)) return Timestamp.valueOf(s);
*/
}
throw inconvertible(s, klass);
}
/** Number .
* @param klass
* @return
* <ul><li> Number true</li>
* <li> false</li>
* </ul>
*/
public static final boolean isNumber(Class<?> klass) {
return Number.class.isAssignableFrom(klass);
}
/** .
* @param obj
* @return
*/
public static final String toString(Object obj) {
if (Assert.isEmpty(obj))
return "";
if (obj instanceof String)
return String.class.cast(obj);
else
return obj.toString();
}
/** Number .
* @param obj
* @return
* <ul><li>Number Number</li>
* <li> Integer(0)</li>
* </ul>
*/
public static final Number toNumber(Object obj) {
if (Assert.isEmpty(obj))
return Integer.valueOf(0);
if (obj instanceof Number)
return Number.class.cast(obj);
if (obj instanceof String) {
String s = (String)obj;
return Double.valueOf(s.replace(",", "").trim());
}
throw inconvertible(obj, Number.class);
}
/** short .
* @param obj
* @return
* <ul><li> short</li>
* <li> 0</li>
* </ul>
*/
public static final short toShort(Object obj) {
return toNumber(obj).shortValue();
}
/** int .
* @param obj
* @return
* <ul><li> int</li>
* <li> 0</li>
* </ul>
*/
public static final int toInt(Object obj) {
return toNumber(obj).intValue();
}
/** long .
* @param obj
* @return
* <ul><li> long</li>
* <li> 0</li>
* </ul>
*/
public static final long toLong(Object obj) {
return toNumber(obj).longValue();
}
/** long .
* @param obj
* @return
* <ul><li> long</li>
* <li> 0</li>
* </ul>
*/
public static final double toDouble(Object obj) {
return toNumber(obj).doubleValue();
}
/** float .
* @param obj
* @return
* <ul><li> float</li>
* <li> 0</li>
* </ul>
*/
public static final float toFloat(Object obj) {
return toNumber(obj).floatValue();
}
/** byte .
* @param obj
* @return
* <ul><li> byte</li>
* <li> 0</li>
* </ul>
*/
public static final byte toByte(Object obj) {
return toNumber(obj).byteValue();
}
/** boolean .
* @param obj
* @return
* <ul><li> boolean</li>
* <li> false</li>
* </ul>
*/
public static final boolean toBoolean(Object obj) {
if (Assert.isEmpty(obj))
return false;
Boolean bool = obj instanceof Boolean ? Boolean.class.cast(obj) : Boolean.valueOf(obj.toString());
return bool.booleanValue();
}
private static final HashMap<Class<?>, Object> ifnull = new HashMap<>();
static {
ifnull.put(char.class, Character.valueOf(' '));
ifnull.put(byte.class, Byte.valueOf("0"));
ifnull.put(short.class, Short.valueOf("0"));
ifnull.put(int.class, Integer.valueOf(0));
ifnull.put(long.class, Long.valueOf(0));
ifnull.put(float.class, Float.valueOf(0));
ifnull.put(double.class, Double.valueOf(0));
ifnull.put(boolean.class, Boolean.FALSE);
}
/** wrapper .
* @param klass wrapper
* @return
* <ul><li>wrapper </li>
* <li> wrapper null</li>
* </ul>
*/
public static final Object primitiveDefault(Class<?> klass) {
return klass != null && klass.isPrimitive() ? ifnull.get(klass) : null;
}
/** \r, \n, \t, .
* @param s
* @return \r, \n, \t,
*/
public static final String rntq(String s) {
return Assert.isEmpty(s) ? "" :
s.replace("\\","\\\\")
.replace("\r","\\r")
.replace("\n","\\n")
.replace("\t","\\t")
.replace("\"","\\\"");
}
private static RuntimeException inconvertible(Object obj, Class<?> klass) {
return new RuntimeException("Inconvertible: " + obj + " to " + klass);
}
/**{@link Convert} .
* <p> Convert .<br />
* Assert Convert .
* </p>
*/
public static interface Support {
/**{@link Convert#toObject(Class, String)} 참고.*/
default Object toObject(Class<?> klass, String s) {
return Convert.toObject(klass, s);
}
/**{@link Convert#isNumber(Class)} 참고.*/
default boolean isNumber(Class<?> klass) {
return Convert.isNumber(klass);
}
/**{@link Convert#toString(Object)} 참고.*/
default String toString(Object obj) {
return Convert.toString(obj);
}
/**{@link Convert#toNumber(Object)} 참고.*/
default Number toNumber(Object obj) {
return Convert.toNumber(obj);
}
/**{@link Convert#toShort(Object)} 참고.*/
default short toShort(Object obj) {
return Convert.toShort(obj);
}
/**{@link Convert#toInt(Object)} 참고.*/
default int toInt(Object obj) {
return Convert.toInt(obj);
}
/**{@link Convert#toLong(Object)} 참고.*/
default long toLong(Object obj) {
return Convert.toLong(obj);
}
/**{@link Convert#toDouble(Object)} 참고.*/
default double toDouble(Object obj) {
return Convert.toDouble(obj);
}
/**{@link Convert#toFloat(Object)} 참고.*/
default float toFloat(Object obj) {
return Convert.toFloat(obj);
}
/**{@link Convert#toByte(Object)} 참고.*/
default byte toByte(Object obj) {
return Convert.toByte(obj);
}
/**{@link Convert#toBoolean(Object)} 참고.*/
default boolean toBoolean(Object obj) {
return Convert.toBoolean(obj);
}
/**{@link Convert#primitiveDefault(Class)} 참고.*/
default Object primitiveDefault(Class<?> klass) {
return Convert.primitiveDefault(klass);
}
/**{@link Convert#rntq(String)} 참고.*/
default String rntq(String s) {
return Convert.rntq(s);
}
}
}

@ -0,0 +1,32 @@
package cokr.xit.foundation.data;
import cokr.xit.foundation.AbstractComponent;
public class DataFormat extends AbstractComponent {
/**'-' .
* @param str '-'
* @return '-'
*/
public static final String corporateNo(String str) {
return !isEmpty(str) ? str.substring(0, 6) + "-" + str.substring(6) : "";
}
/**'-' .
* @param str '-'
* @return '-'
*/
public static final String businessNo(String str) {
return !isEmpty(str) ? str.substring(0, 3) + "-" + str.substring(3, 5) + "-" + str.substring(5) : "";
}
/**'-' (yyyy-MM-dd) .
* @param str '-'
* @return '-'
*/
public static final String yyyy_mm_dd(String str) {
if (isEmpty(str)) return "";
return str.substring(0, 4) + "-" + str.substring(4, 6) + "-" + str.substring(6);
}
}

@ -0,0 +1,127 @@
package cokr.xit.foundation.data;
import java.util.Map;
import java.util.function.Supplier;
import cokr.xit.foundation.Assert;
/**<p> .
* </p>
* <p> .
* </p>
*/
public class DataObject extends StringMap<Object> {
private static final long serialVersionUID = 1L;
/**map key value DataObject .
* @param map Map
* @return DataObject
*/
public static DataObject create(Map<String, ?> map) {
if (map == null) return null;
if (map instanceof DataObject) return (DataObject)map;
DataObject result = new DataObject();
map.forEach(result::put);
return result;
}
/**DataObject .
*/
public DataObject() {
caseSensitiveKey(false);
}
/**lv rv .
* @param lv
* @param rv
* @return
* <ul><li>lv rv true</li>
* <li> false</li>
* </ul>
*/
protected static boolean equals(Object lv, Object rv) {
return lv == rv ? true : lv != null && lv.equals(rv);
}
/**{@link Assert#isEmpty(Object) Assert.isEmpty(...)} .
*/
protected static boolean isEmpty(Object obj) {
return Assert.isEmpty(obj);
}
/**{@link Assert#ifEmpty(Object, Supplier) Assert.ifEmpty(...)} 참고*/
protected static <T> T ifEmpty(T t, Supplier<T> nt) {
return Assert.ifEmpty(t, nt);
}
/**{@link Assert#notEmpty(Object, String) Assert.notEmpty(...)} .
*/
protected static <T> T notEmpty(T t, String name) {
return Assert.notEmpty(t, name);
}
/** .
* @param names
* @return DataObject
*/
public DataObject notEmpty(String... names) {
for (String name: names)
notEmpty(get(name), name);
return this;
}
@SuppressWarnings("unchecked")
/** T .
* @param name
* @return T
* @throws ClassCastException
*/
public <T> T value(String name) {
return (T)get(name);
}
/** String .
* @param name
* @return String
*/
public String string(String name) {
Object obj = get(name);
return isEmpty(obj) ? "" : obj instanceof String ? (String)obj : obj.toString().trim();
}
/** Number .
* @param name
* @return
* <ul><li>Number </li>
* <li> Integer(0)</li>
* </ul>
*/
public Number number(String name) {
Object obj = get(name);
if (obj == null)
return Integer.valueOf(0);
if (obj instanceof Number)
return Number.class.cast(obj);
if (obj instanceof String)
return Double.valueOf((String)obj);
throw new RuntimeException("The Object named '" + name + "' is not a Number");
}
/** boolean .
* @param name
* @return
* <ul><li>boolean </li>
* <li> false</li>
* </ul>
*/
public boolean bool(String name) {
Object obj = get(name);
if (obj == null)
return false;
Boolean bool = obj instanceof Boolean ? Boolean.class.cast(obj) : Boolean.valueOf(obj.toString());
return bool.booleanValue();
}
}

@ -0,0 +1,87 @@
package cokr.xit.foundation.data;
import java.io.InputStream;
import com.fasterxml.jackson.core.JsonParser.Feature;
import com.fasterxml.jackson.databind.ObjectMapper;
import cokr.xit.foundation.AbstractComponent;
/**JSON / .
* @author mjkhan
*/
public class JSON extends AbstractComponent {
private ObjectMapper objectMapper;
/**JSON / ObjectMapper .
* @return JSON / ObjectMapper
*/
public ObjectMapper getObjectMapper() {
if (objectMapper == null) {
objectMapper = new ObjectMapper();
objectMapper.configure(Feature.ALLOW_COMMENTS, true);
}
return objectMapper;
}
/**JSON / ObjectMapper .
* @param objectMapper JSON / ObjectMapper
* @return JSON
*/
public JSON setObjectMapper(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
return this;
}
/**JSON .
* @param <T>
* @param json JSON
* @param klass
* @return
*/
public <T> T parse(String json, Class<T> klass) {
try {
return getObjectMapper().readValue(json, klass);
} catch (Exception e) {
throw runtimeException(e);
}
}
/**input .
* @param <T>
* @param input JSON input
* @param klass
* @return input
*/
public <T> T parse(InputStream input, Class<T> klass) {
try {
return getObjectMapper().readValue(input, klass);
} catch (Exception e) {
throw runtimeException(e);
}
}
/** JSON .
* @param obj
* @return JSON
*/
public String stringify(Object obj) {
return stringify(obj, false);
}
/** JSON .
* @param obj
* @param indent
* <ul><li> true</li>
* <li> false</li>
* </ul>
* @return JSON
*/
public String stringify(Object obj, boolean indent) {
try {
return getObjectMapper().writeValueAsString(obj);
} catch (Exception e) {
throw runtimeException(e);
}
}
}

@ -0,0 +1,44 @@
package cokr.xit.foundation.data;
import cokr.xit.foundation.Assert;
/**
* @author mjkhan
*/
public enum ProcType {
/** 데이터 생성 */
CREATE("C"),
/** 데이터 수정 */
UPDATE("U"),
/** 데이터 삭제 */
DELETE("D");
private final String code;
private ProcType(String code) {
this.code = code;
}
/** .
* @return
*/
public String getCode() {
return code;
}
/** ProcType .
* @param code
* @return ProcType
*/
public static ProcType codeOf(String code) {
if (Assert.isEmpty(code))
return null;
for (ProcType procType: values()) {
if (procType.code.equals(code))
return procType;
}
throw new IllegalArgumentException("code: " + code);
}
}

@ -0,0 +1,54 @@
package cokr.xit.foundation.data;
import java.io.Reader;
import java.sql.CallableStatement;
import java.sql.Clob;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import cokr.xit.foundation.Assert;
public class RowValueHandler extends BaseTypeHandler<Object> {
@Override
public void setNonNullParameter(PreparedStatement pstmt, int i, Object parameter, JdbcType jdbcType) throws SQLException {
pstmt.setObject(i, parameter);
}
@Override
public Object getNullableResult(ResultSet resultSet, String columnName) throws SQLException {
Object obj = resultSet.getObject(columnName);
return obj instanceof Clob ? clobToString(obj) : obj;
}
@Override
public Object getNullableResult(ResultSet resultSet, int columnIndex) throws SQLException {
Object obj = resultSet.getObject(columnIndex);
return obj instanceof Clob ? clobToString(obj) : obj;
}
@Override
public Object getNullableResult(CallableStatement cstmt, int columnIndex) throws SQLException {
return cstmt.getObject(columnIndex);
}
private String clobToString(Object obj) {
if (!(obj instanceof Clob))
return null;
try {
Clob clob = Clob.class.cast(obj);
Reader reader = clob.getCharacterStream();
char[] chars = new char[1024];
StringBuilder buffer = new StringBuilder();
while ((reader.read(chars)) != -1)
buffer.append(chars);
return buffer.toString();
} catch (Exception e) {
throw Assert.runtimeException(e);
}
}
}

@ -0,0 +1,136 @@
package cokr.xit.foundation.data;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;
/**String E Map .<br />
* {@link #caseSensitiveKey(boolean) } .<br />
* ..
* @param <E>
*/
public class StringMap<E> extends LinkedHashMap<String, E> {
/**objs groupMapper grouping .
* @param objs
* @param groupMapper
* @return groupMapper grouping Map
*/
public static <E> Map<String, List<E>> groupBy(Collection<E> objs, Function<E, String> groupMapper) {
return objs != null ?
objs.stream().collect(Collectors.groupingBy(groupMapper)) :
Collections.emptyMap();
}
private static final long serialVersionUID = 1L;
private boolean caseSensitiveKey = true;
/** .
* @return
* <ul><li> true</li>
* <li> false</li>
* </ul>
*/
public boolean caseSensitiveKey() {
return caseSensitiveKey;
}
/** .
* @param sensitive
* <ul><li> true</li>
* <li> false</li>
* </ul>
* @return StringMap
*/
public <T extends StringMap<E>> T caseSensitiveKey(boolean sensitive) {
caseSensitiveKey = sensitive;
return self();
}
private String findKey(Object obj) {
String s = (String)obj;
if (caseSensitiveKey)
return s;
for (String key: keySet())
if (key.equalsIgnoreCase(s))
return key;
return s;
}
@Override
public boolean containsKey(Object key) {
return super.containsKey(key) ? true : super.containsKey(findKey(key));
}
@Override
public E get(Object key) {
E t = super.get(key);
return t != null ? t : super.get(findKey(key));
}
@Override
public E getOrDefault(Object key, E defaultValue) {
return super.getOrDefault(findKey(key), defaultValue);
}
@Override
public E put(String key, E value) {
return super.put(findKey(key), value);
}
/**value key .
* @param key
* @param value
* @return StringMap
*/
public <T extends StringMap<E>> T set(String key, E value) {
put(key, value);
return self();
}
@Override
public E remove(Object key) {
E t = super.remove(key);
return t != null ? t : super.remove(findKey(key));
}
@Override
public E computeIfAbsent(String key, Function<? super String, ? extends E> mappingFunction) {
return super.computeIfAbsent(findKey(key), mappingFunction);
}
@Override
public E computeIfPresent(String key, BiFunction<? super String, ? super E, ? extends E> remappingFunction) {
return super.computeIfPresent(findKey(key), remappingFunction);
}
@Override
public E merge(String key, E value, BiFunction<? super E, ? super E, ? extends E> remappingFunction) {
return super.merge(findKey(key), value, remappingFunction);
}
@Override
public E putIfAbsent(String key, E value) {
return super.putIfAbsent(findKey(key), value);
}
/** key value .
* @param key
* @param value
* @return StringMap
*/
public <T extends StringMap<E>> T setIfAbsent(String key, E value) {
putIfAbsent(key, value);
return self();
}
@SuppressWarnings("unchecked")
protected <T extends StringMap<E>> T self() {
return (T)this;
}
}

@ -0,0 +1,193 @@
package cokr.xit.foundation.data;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.nio.charset.Charset;
import java.util.HashMap;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import cokr.xit.foundation.AbstractComponent;
/**XML /
* @author mjkhan
*/
public class XML extends AbstractComponent {
private String charset;
private HashMap<Class<?>, Support> xctxes;
/** XML() .
* @param charset . .
*/
public XML(String charset) {
this.charset = ifEmpty(charset, () -> Charset.defaultCharset().name());
}
private Support jaxb(Class<?> klass) throws Exception {
if (xctxes == null)
xctxes = new HashMap<>();
Support support = xctxes.get(klass);
if (support == null) {
JAXBContext xctx = JAXBContext.newInstance(klass);
xctxes.put(klass, support = new Support(xctx, charset));
}
return support;
}
/**xml .
* @param <T>
* @param str xml
* @param klass
* @return xml
*/
public <T> T parse(String str, Class<T> klass) {
try {
return klass.cast(jaxb(klass).unmarshal(str));
} catch (Exception e) {
throw runtimeException(e);
}
}
/**xml input .
* @param <T>
* @param input xml input
* @param klass
* @return xml input
*/
public <T> T parse(InputStream input, Class<T> klass) {
try {
return klass.cast(jaxb(klass).unmarshal(input));
} catch (Exception e) {
throw runtimeException(e);
}
}
/**xml .
* @param <T>
* @param file xml
* @param klass
* @return xml
*/
public <T> T parse(File file, Class<T> klass) {
try (FileInputStream input = new FileInputStream(file)) {
return parse(input, klass);
} catch (Exception e) {
throw runtimeException(e);
}
}
/** xml .<br />
* JAXB(Java Architecture for XML Binding - javax.xml.*) .
* <pre><code> &#64;XmlRootElement
* &#64;XmlType
* &#64;XmlElement
* &#64;XmlAttribute
* &#64;XmlTransient
* </code></pre>
* @param obj
* @return xml
*/
public String stringify(Object obj) {
try {
return jaxb(obj.getClass()).stringify(obj);
} catch (Exception e) {
throw runtimeException(e);
}
}
/** xml out .<br />
* JAXB(Java Architecture for XML Binding - javax.xml.*) .
* <pre><code> &#64;XmlRootElement
* &#64;XmlType
* &#64;XmlElement
* &#64;XmlAttribute
* &#64;XmlTransient
* </code></pre>
* @param obj
* @param out OutputStream
*/
public void write(Object obj, OutputStream out) {
try {
jaxb(obj.getClass()).marshal(obj, out);
} catch (Exception e) {
throw runtimeException(e);
}
}
/** xml .<br />
* JAXB(Java Architecture for XML Binding - javax.xml.*) .
* <pre><code> {@code @XmlRootElement}
* {@code @XmlType}
* {@code @XmlElement}
* {@code @XmlAttribute}
* {@code @XmlTransient}</code></pre>
* @param obj
* @param file
*/
public void write(Object obj, File file) {
try (FileOutputStream out = new FileOutputStream(file)) {
write(obj, out);
} catch (Exception e) {
throw runtimeException(e);
}
}
private static class Support {
String charset;
JAXBContext xctx;
Marshaller marshaller;
Unmarshaller unmarshaller;
Support(JAXBContext xctx, String charset) {
this.xctx = xctx;
this.charset = charset;
}
Object unmarshal(String input) throws Exception {
if (unmarshaller == null) {
unmarshaller = xctx.createUnmarshaller();
}
try (StringReader reader = new StringReader(input)) {
return unmarshaller.unmarshal(reader);
} catch (Exception e) {
throw e;
}
}
Object unmarshal(InputStream input) throws Exception {
if (unmarshaller == null) {
unmarshaller = xctx.createUnmarshaller();
}
return unmarshaller.unmarshal(input);
}
Marshaller marshaller() throws Exception {
if (marshaller == null) {
marshaller = xctx.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty(Marshaller.JAXB_ENCODING, charset);
}
return marshaller;
}
String stringify(Object obj) throws Exception {
try (StringWriter writer = new StringWriter()) {
marshaller().marshal(obj, writer);
return writer.toString();
} catch (Exception e) {
throw e;
}
}
void marshal(Object obj, OutputStream out) throws Exception {
marshaller().marshal(obj, out);
}
}
}

@ -0,0 +1,107 @@
package cokr.xit.foundation.data.hierarchy;
import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import cokr.xit.foundation.AbstractComponent;
/** {@link HierarchyBuilder} .<br />
* Hierarchy
* <ul><li>{@link #getElements() }</li>
* <li>{@link #getIndex() }</li>
* <li>{@link #topElements() }</li>
* <li>{@link #getTop() }</li>
* <li>{@link #get(String) }</li>
* </ul>
* .
* @param <T>
*/
public class Hierarchy<T> extends AbstractComponent implements Serializable {
private static final long serialVersionUID = 1L;
/** .
* @param objs
* @param getChildren function
* @return
*/
public static <T> String toString(Iterable<T> objs, Function<T, Iterable<T>> getChildren) {
return new Stringify<T>()
.beginElement((e, level, index) -> {
String str = index == 0 && level == 0 ? "" : "\n";
if (level > 0)
str += Stringify.indent(" ", level) + "+-";
return str += e;
})
.getChildren(getChildren)
.get(objs);
}
private Collection<T> elements;
private List<T> tops;
private Map<String, T> index;
/**Hierarchy .
* @return
* <ul><li>Hierarchy true</li>
* <li> false</li>
* </ul>
*/
public boolean isEmpty() {
return isEmpty(index) || isEmpty(elements);
}
/**Hierarchy .
* @return Hierarchy
*/
public Map<String, T> getIndex() {
return ifEmpty(index, () -> Collections.emptyMap());
}
Hierarchy<T> setIndex(Map<String, T> index) {
this.index = index;
return this;
}
/**Hierarchy .
* @return Hierarchy
*/
public Collection<T> getElements() {
return elements;
}
Hierarchy<T> setElements(Collection<T> elements) {
this.elements = elements;
return this;
}
/**Hierarchy .
* @return Hierarchy
*/
public List<T> topElements() {
return ifEmpty(tops, () -> Collections.emptyList());
}
/**Hierarchy .
* @return Hierarchy
*/
public T getTop() {
return !isEmpty() ? tops.iterator().next() : null;
}
Hierarchy<T> setTops(List<T> tops) {
this.tops = tops;
return this;
}
/** .
* @param elementID
* @return
*/
public T get(String elementID) {
return !isEmpty() ? index.get(elementID) : null;
}
}

@ -0,0 +1,278 @@
package cokr.xit.foundation.data.hierarchy;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
/**Hierarchy .
* <p>HierarchyBuilder Hierarchy
* <ul><li> {@link #setElements(Collection) }</li>
* <li>{@link #setInstruction(Instruction) Instruction} .</li>
* </ul>
* {@link Instruction} HierarchyBuilder Hierarchy .
*
* <p> Instruction HierarchyBuilder {@link #build() } .<br />
* HierarchyBuilder {@link Hierarchy} .<br />
* Hierarchy {@link #build(Supplier)} .<br />
* </p>
* <p> HierarchyBuilder .
* <pre class="shade">{@code Collection<MyObject> elements = ...;
* HierarchyBuilder.Instruction<MyObject> instruction = new HierarchyBuilder.Instruction<>()
* .getID(e -> e.getId())
* .getParentID(e -> e.getParentId())
* .addChild((parent, child) -> parent.add(child))
* .atTop(e -> e.getParentId() == null || e.getId().equals(e.getParentId()));
* HierarchyBuilder<MyObject> builder = new HierarchyBuilder<>()
* .setInstruction(instruction);
* .setElements(elements);
* Hierarchy<MyObject> hierarchy = builder.build();
* List<MyObject> tops = hierarchy.topElements();
* MyObject root = hierarchy.getTop();}</pre>
* :
* <pre class="shade">{@code ...
* Hierarchy<MyObject> hierarchy = new HierarchyBuilder<MyObject>()
* .getID(e -> e.getId())
* .getParentID(e -> e.getParentId())
* .addChild((parent, child) -> parent.add(child))
* .atTop(e -> e.getParentId() == null || e.getId().equals(e.getParentId()))
* .setElements(elements)
* .build();
* ...}</pre>
*
*/
public class HierarchyBuilder<T> {
private Collection<T> elements;
private HashMap<String, T> index;
private Instruction<T> instruction;
/** .
* @param elements
* @return HierarchyBuilder
*/
public HierarchyBuilder<T> setElements(Collection<T> elements) {
if (elements == null)
throw new IllegalArgumentException("elements: null");
this.elements = elements;
createIndex();
return this;
}
private Instruction<T> instruction() {
return instruction != null ? instruction : (instruction = new Instruction<>());
}
/** Instruction .
* @param instruction Instruction
* @return HierarchyBuilder
*/
public HierarchyBuilder<T> setInstruction(Instruction<T> instruction) {
this.instruction = instruction;
return this;
}
/**{@link Instruction#atTop(Predicate)} .
* @return HierarchyBuilder
*/
public HierarchyBuilder<T> atTop(Predicate<T> test) {
instruction().atTop(test);
return this;
}
/**{@link Instruction#getID(Function)} .
* @return HierarchyBuilder
*/
public HierarchyBuilder<T> getID(Function<T, String> func) {
instruction().getID(func);
return this;
}
/**{@link Instruction#getParentID(Function)} .
* @return HierarchyBuilder
*/
public HierarchyBuilder<T> getParentID(Function<T, String> func) {
instruction().getParentID(func);
return this;
}
/**{@link Instruction#addChild(BiConsumer)}
* @return HierarchyBuilder
*/
public HierarchyBuilder<T> addChild(BiConsumer<T, T> func) {
instruction().addChild(func);
return this;
}
private void createIndex() {
index = new HashMap<String, T>();
for (T e: elements)
index.put(instruction.getID.apply(e), e);
}
/** .
* @return
*/
public Map<String, T> getIndex() {
return index;
}
private void add(T parent, T child) {
if (parent == null || child == null || parent == child) return;
instruction.addChild.accept(parent, child);
}
/** .
* @param rootID ID
* @return
*/
public T get(String rootID) {
if (elements == null) return null;
T root = index.get(rootID);
if (root == null)
throw new RuntimeException("Root element not found: " + rootID);
for (T element: elements) {
if (element == null) continue;
String parentID = instruction.getParentID.apply(element);
T parent = parentID == null ? null : index.get(parentID);
add(parent, element);
}
return root;
}
/** .
* @return
*/
public List<T> get() {
if (elements == null) return Collections.emptyList();
ArrayList<T> tops = new ArrayList<T>();
for (T e: elements) {
boolean top = instruction.atTop != null && instruction.atTop.test(e);
if (top) {
if (!tops.contains(e))
tops.add(e);
} else {
String parentID = instruction.getParentID.apply(e);
T parent = parentID != null ? index.get(parentID) : null;
if (parent == null || parent.equals(e)) {
if (!tops.contains(e))
tops.add(e);
} else {
add(parent, e);
}
}
}
return tops;
}
/**Hierarchy .
* @return Hierarchy
*/
public Hierarchy<T> build() {
return build(Hierarchy::new);
}
/**Hierarchy .<br />
* The Hierarchy is an instance of the class that the factory supplies.
* @param factory Hierarchy
* @return Hierarchy
*/
public <H extends Hierarchy<T>> H build(Supplier<H> factory) {
List<T> tops = get();
H h = factory.get();
h.setElements(elements).setIndex(index).setTops(tops);
return h;
}
/**HierarchyBuilder .
*/
public void clear() {
if (index != null)
index.clear();
if (instruction != null)
instruction.clear();
elements = null;
}
/**HierarchyBuilder Hierarchy
* <ul><li>{@link #getID(Function) ID}</li>
* <li>{@link #getParentID(Function) ID}</li>
* <li>{@link #addChild(BiConsumer) } </li>
* <li>{@link #atTop(Predicate) } </li>
* </ul>
* .
* @param <T>
*/
public static class Instruction<T> {
private Function<T, String>
getID,
getParentID;
private BiConsumer<T, T> addChild;
private Predicate<T> atTop;
/** Instruction .
*/
public Instruction() {
clear();
}
/** ID .<br />
* ID ID , .<br />
* HierarchyBuilder .<br />
* @param func ID
* @return Instruction
*/
public Instruction<T> getID(Function<T, String> func) {
this.getID = func;
return this;
}
/** ID .
* @param func ID
* @return Instruction
*/
public Instruction<T> getParentID(Function<T, String> func) {
this.getParentID = func;
return this;
}
/** .
* @param consumer , , .
* @return Instruction
*/
public Instruction<T> addChild(BiConsumer<T, T> consumer) {
this.addChild = consumer;
return this;
}
/** .<br />
* HierarchyBuilder true .
* @param test
* @return Instruction
*/
public Instruction<T> atTop(Predicate<T> test) {
this.atTop = test;
return this;
}
/**Instruction .
* @return Instruction
*/
public Instruction<T> clear() {
getID = (t) -> "";
getParentID = (t) -> "";
addChild = (t1, t2) -> {};
atTop = null;
return this;
}
}
}

@ -0,0 +1,235 @@
package cokr.xit.foundation.data.hierarchy;
import java.util.Collections;
import java.util.function.Function;
import cokr.xit.foundation.AbstractComponent;
/**Utility to convert objects of a hierarchy to string representation.
* <p>For a Stringify to convert objects of a hierarchy, you should
* <ul><li>Set an {@link #setInstruction(Instruction) Instruction} for steps to convert the objects</li>
* <li>Call {@link #get(Iterable)} with the objects as an argument</li>
* </ul>
* </p>
* <p>An {@link Instruction} is a set of steps for a Stringify to perform the conversion.<br />
* For convenience, a Stringify has methods that sets the steps to an internal instruction.
* </p>
*/
class Stringify<T> extends AbstractComponent {
/**A functional interface that converts an object to a string
* @param <T> an object type
*/
@FunctionalInterface
public interface ToString<T> {
/**Converts t to a string.
* @param t an object
* @param level 0-based level or depth of t in a hierarchy
* @param index 0-based index of t
* @return string representation of t
*/
String get(T t, int level, int index);
}
private Instruction<T> instruction;
/**Returns indentation with s appended n times.
* @param s indentation string
* @param n number of times to append indentation string
* @return indentation string appended n time
*/
public static String indent(String s, int n) {
String result = "";
for (int i = 0; i < n; ++i) {
result += s;
}
return result;
}
private Instruction<T> instruction() {
return instruction != null ? instruction : (instruction = new Instruction<>());
}
/**Sets an instruction to convert objects to string representation.
* @param instruction instruction to convert objects to string representation
* @return this Stringify
*/
public Stringify<T> setInstruction(Instruction<T> instruction) {
this.instruction = instruction;
return this;
}
/**See {@link Instruction#beginElement(ToString)}
* @return this Stringify
*/
public Stringify<T> beginElement(ToString<T> func) {
instruction().beginElement(func);
return this;
}
/**See {@link Instruction#endElement(ToString)}
* @return this Stringify
*/
public Stringify<T> endElement(ToString<T> func) {
instruction().endElement(func);
return this;
}
/**See {@link Instruction#beginChildren(ToString)}
* @return this Stringify
*/
public Stringify<T> beginChildren(ToString<T> func) {
instruction().beginChildren(func);
return this;
}
/**See {@link Instruction#endChildren(ToString)}
* @return this Stringify
*/
public Stringify<T> endChildren(ToString<T> func) {
instruction().endChildren(func);
return this;
}
/**See {@link Instruction#getChildren(Function)}
* @return this Stringify
*/
public Stringify<T> getChildren(Function<T, Iterable<T>> func) {
instruction().getChildren(func);
return this;
}
/**Converts elements to string representation.
* @param elements objects of a hierarchy
* @return string representation of the elements
*/
public String get(Iterable<T> elements) {
if (isEmpty(elements)) return "";
StringBuilder buff = new StringBuilder();
toString(elements, buff, 0);
return buff.toString();
}
private void toString(Iterable<T> elements, StringBuilder buff, int level) {
Instruction<T> instr = instruction();
int index = 0;
for (T e: elements) {
buff.append(instr.beginElement().get(e, level, index));
Iterable<T> children = instr.getChildren().apply(e);
int sublevel = level + 1;
if (!isEmpty(children)) {
buff.append(instr.beginChildren().get(e, sublevel, index));
toString(children, buff, sublevel);
buff.append(instr.endChildren().get(e, sublevel, index));
}
buff.append(instr.endElement().get(e, level, index));
++index;
}
}
/**Is a set of steps to convert objects of a hierarchy to string representation.
* <p>With an Instruction, you specify how to
* <ul><li>{@link #beginElement(ToString) Mark the beginning of an element} with a string</li>
* <li>{@link #endElement(ToString) Mark the end of an element} with a string</li>
* <li>{@link #getChildren(Function) Get child elements} of an element</li>
* <li>{@link #beginChildren(ToString) Mark the beginning of child elements} with a string</li>
* <li>{@link #endChildren(ToString) Mark the end of child elements} with a string</li>
* </ul>
* </p>
* @param <T> an object type
*/
public static class Instruction<T> {
private ToString<T>
beginElement,
endElement,
beginChildren,
endChildren;
private Function<T, Iterable<T>> getChildren;
/**Creates a new Instruction.
*/
public Instruction() {
clear();
}
ToString<T> beginElement() {
return beginElement;
}
/**Sets a function that returns a string to mark the beginning of an element.
* @param func function that returns a string to mark the beginning of an element
* @return this Instruction
*/
public Instruction<T> beginElement(ToString<T> func) {
this.beginElement = func;
return this;
}
ToString<T> endElement() {
return endElement;
}
/**Sets a function that returns a string to mark the end of an element.
* @param func function that returns a string to mark the end of an element
* @return this Instruction
*/
public Instruction<T> endElement(ToString<T> func) {
this.endElement = func;
return this;
}
ToString<T> beginChildren() {
return beginChildren;
}
/**Sets a function that returns a string to mark the beginning of child elements.
* @param func function that returns a string to mark the beginning of child elements
* @return this Instruction
*/
public Instruction<T> beginChildren(ToString<T> func) {
this.beginChildren = func;
return this;
}
ToString<T> endChildren() {
return endChildren;
}
/**Sets a function that returns a string to mark the end of child elements.
* @param func function that returns a string to mark the end of child elements
* @return this Instruction
*/
public Instruction<T> endChildren(ToString<T> func) {
this.endChildren = func;
return this;
}
Function<T, Iterable<T>> getChildren() {
return getChildren;
}
/**Sets a function that returns child elements of the current element.
* @param getChildren function that returns child elements of the current element
* @return this Instruction
*/
public Instruction<T> getChildren(Function<T, Iterable<T>> getChildren) {
this.getChildren = getChildren;
return this;
}
/**Clears the Instruction to the initial state.
* @return this Instruction
*/
public Instruction<T> clear() {
ToString<T> empty = (e, level, index) -> "";
beginElement = empty;
endElement = empty;
beginChildren = empty;
endChildren = empty;
getChildren = t -> Collections.emptyList();
return this;
}
}
}

@ -0,0 +1,3 @@
/**
*/
package cokr.xit.foundation.data.hierarchy;

@ -0,0 +1,3 @@
/**
*/
package cokr.xit.foundation.data;

@ -0,0 +1,226 @@
package cokr.xit.foundation.data.paging;
import java.util.ArrayList;
import java.util.Map;
/** .
* <p>BoundedList .<br />
* , 20 BoundedList .</p>
* <p> BoundedList .<br />
* BoundedList .
* <ul><li> {@link #setTotalSize(int) }</li>
* <li>{@link #setFetchSize(int) }</li>
* <li> {@link #setStart(int) }(0 )</li>
* </ul>
* <p>BoundedList 0 .</p>
* <p>BoundedList {@link #hasMore() } {@link #hasNext() } {@link #hasPrevious() } .</p>
* @param <E>
*/
public class BoundedList<E> extends ArrayList<E> {
private static final long serialVersionUID = 1L;
private int
current,
fetchSize,
start;
private long totalSize;
/** .
* @return
*/
public int getFetchSize() {
return fetchSize;
}
/** .
* @param size
* @return BoundedList
*/
public BoundedList<E> setFetchSize(int size) {
if (size < 0)
throw new IllegalArgumentException("fetchSize < 0");
this.fetchSize = size;
return this;
}
/** .
* @return
*/
public long getTotalSize() {
if (isEmpty())
return 0;
if (totalSize > 0)
return totalSize;
if (totalSize < 1) {
E first = get(0);
if (first instanceof Map) {
Map<String, ?> row = (Map<String, ?>)first;
totalSize = Pageable.getTotalSize(row);
} else if (first instanceof Pageable) {
Pageable row = (Pageable)first;
totalSize = row.getTotalSize();
}
return totalSize;
}
return totalSize = size();
}
/** .
* @param totalSize
*/
public BoundedList<E> setTotalSize(long totalSize) {
this.totalSize = totalSize;
return this;
}
/** .
* @return (0 )
*/
public int getStart() {return isEmpty() ? -1 : start;}
/** .
* @param start (0 )
*/
public BoundedList<E> setStart(int start) {
this.start = start;
// this.start = totalSize < 1 ? -1 : start;
return this;
}
/** .
* @return (0 )
*/
public int getEnd() {
return isEmpty() ? -1 : start + size() - 1;
}
/** .
* @return
*/
public int current() {
return isEmpty() ? -1 : current;
}
/** .
* @param index
*/
public BoundedList<E> setCurrent(int index) {
if (index < 0) {
current = index;
return this;
}
else if (get(index) != null) current = index;
return this;
}
/** .
* @return
* <ul><li> true</li>
* <li> false</li>
* </ul>
*/
public boolean hasMore() {
return !isEmpty() && size() < getTotalSize();
}
/** .
* @return
* <ul><li> true</li>
* <li> false</li>
* </ul>
*/
public boolean hasPrevious() {
return hasMore() && start > 0;
}
/** .
* @return
* <ul><li> true</li>
* <li> false</li>
* </ul>
*/
public boolean hasNext() {
return hasMore() && getEnd() < getTotalSize() - 1;
}
/** .
* @return
*/
public E get() {
return get(current);
}
@Override
public boolean add(E e) {
if (e == null || contains(e)) return false;
boolean result = super.add(e);
++totalSize;
return result;
}
@Override
public void add(int index, E e) {
super.add(index, e);
++totalSize;
}
@Override
public E remove(int index) {
E e = super.remove(index);
if (e != null)
--totalSize;
return e;
}
@Override
public void clear() {
super.clear();
totalSize = 0;
start = -1;
}
/**BoundedList .
*/
public BoundedList<E> init() {
totalSize = size();
return this;
}
/**페이징 처리를 위한 값들을 계산하기 위한 유틸리티*/
public static class Fetch {
public static final int
ALL = 0,
NONE = -1;
private Fetch() {}
/**Returns the number of fetches needed to provide all elements.
* @param elementCount number of all elements
* @param size size or number of elements in a fetch
* @return number of fetches needed to provide all elements
*/
public static final int count(int elementCount, int size) {
if (elementCount == 0 || size == ALL) return 1;
return (elementCount / size) + ((elementCount % size) == 0 ? 0 : 1);
}
/**Returns the end index of the elements starting from the start index.
* @param elementCount number of all elements
* @param size size or number of elements in a fetch
* @param start 0-based start index
* @return 0-based end index of the
*/
public static final int end(int elementCount, int size, int start) {
if (size < ALL)
throw new IllegalArgumentException("Invalid size: " + size);
if (elementCount < 0)
throw new IllegalArgumentException("Invalid elementCount: " + elementCount);
int last = elementCount - 1;
if (size == ALL) return last;
return Math.min(last, start + size -1);
}
/**
* @param current
* @param count
* @return
*/
public static final int page(int current, int count) {
return count < 1 ? 0 : current / count;
}
/**
* @param page
* @param visibleLinks
* @return
*/
public static final int band(int page, int visibleLinks) {
return visibleLinks < 1 ? 0 : page / visibleLinks;
}
}
}

@ -0,0 +1,71 @@
package cokr.xit.foundation.data.paging;
import java.util.Map;
import cokr.xit.foundation.data.Convert;
/** ,
* <ul><li> </li>
* <li> </li>
* </ul>
*
* @author mjkhan
*/
public interface Pageable {
/** Map .<br />
* "pageNum" .
* @param map
* @return
*/
static int getPageNum(Map<String, ?> map) {
return Convert.toInt(map.get("pageNum"));
}
/** Map .<br />
* "fetchSize" .
* @param map
* @return
*/
static int getFetchSize(Map<String, ?> map) {
return Convert.toInt(map.get("fetchSize"));
}
/** Map .<br />
* "TOT_CNT" .
* @param map
* @return
*/
static long getTotalSize(Map<String, ?> map) {
return Convert.toLong(map.get("TOT_CNT"));
}
/** , .
* @return
*/
default int getPageNum() {return 0;}
/** , .
* @param pageNum
*/
default void setPageNum(int pageNum) {}
/** , .
* @return
*/
default int getFetchSize() {return 0;}
/** , .
* @param fetchSize
*/
default void setFetchSize(int fetchSize) {}
/** , .
* @return
*/
default long getTotalSize() {return 0;}
/** , .
* @param totalSize
*/
default void setTotalSize(long totalSize) {}
}

@ -0,0 +1,96 @@
package cokr.xit.foundation.data.paging;
import java.sql.Statement;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import cokr.xit.foundation.AbstractComponent;
import cokr.xit.foundation.component.QueryRequest;
/** MyBatis Interceptor
* @author mjkhan
*/
@Intercepts({
@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
@Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class})
})
public class PagingSupport extends AbstractComponent implements Interceptor {
private boolean paging;
private int pageNum;
private int fetchSize;
@Override
public Object intercept(Invocation invocation) throws Throwable {
switch (getStep(invocation)) {
case "Executor.query": return setPaging(invocation);
case "ResultSetHandler.handleResultSets": return setPagingInfo(invocation);
default: return invocation.proceed();
}
}
private static final Class<?>[] handlers = {Executor.class, ResultSetHandler.class};
private String getStep(Invocation invocation) {
Object obj = invocation.getTarget();
String result = "";
for (Class<?> klass: handlers) {
if (klass.isInstance(obj)) {
result = klass.getSimpleName();
break;
}
}
return result += "." + invocation.getMethod().getName();
}
private Object setPaging(Invocation invocation) throws Exception {
Object[] args = invocation.getArgs();
Object arg = args[1];
if (arg instanceof Map) {
@SuppressWarnings("unchecked")
Map<String, ?> params = (Map<String, ?>)arg;
fetchSize = Pageable.getFetchSize(params);
pageNum = Pageable.getPageNum(params);
} else if (arg instanceof QueryRequest) {
QueryRequest req = (QueryRequest)arg;
fetchSize = req.getFetchSize();
pageNum = req.getPageNum();
} else if (arg instanceof Pageable) {
Pageable pageable = (Pageable)arg;
fetchSize = pageable.getFetchSize();
pageNum = pageable.getPageNum();
}
paging = pageNum > 0 && fetchSize > 0;
return invocation.proceed();
}
private Object setPagingInfo(Invocation invocation) throws Exception {
Object obj = invocation.proceed();
if (paging && (obj instanceof List)) {
List<?> list = (List<?>)obj;
BoundedList<Object> boundedList = new BoundedList<>();
boundedList.setFetchSize(fetchSize);
boundedList.addAll(list);
if (!boundedList.isEmpty()) {
boundedList.setStart((pageNum - 1) * fetchSize);
}
obj = boundedList;
}
paging = false;
pageNum = fetchSize = 0;
return obj;
}
}

@ -0,0 +1,62 @@
/**<b> </b>
* <p> , .<br />
* .
* <p><b>{@link PagingSupport} </b>
* <p>PagingSupport sql/mybatis-config.xml .
* <pre>{@code <plugins>
* <plugin interceptor="cokr.xit.foundation.data.paging.PagingSupport" />
* </plugins>
* }</pre>
* <p><b>SELECT </b><br />
* SELECT
* <ul><li>{@code <include refid="utility.paging-prefix" />}</li>
* <li>{@code <include refid="utility-paging-suffix" />}</li>
* </ul>
* include.
* <pre>{@code <select id="selectATable" parameterType="..." resultType="...">
* <include refid="utility.paging-prefix" />
* SELECT *
* FROM A_TABLE
* WHERE ...
* ORDER BY ...
* <include refid="utility.paging-suffix" />}</pre>
* <ul><li>parameterType - {@code <select .../>} parameterType .
* <ul><li>map</li>
* <li>{@link cokr.xit.foundation.component.QueryRequest} </li>
* <li>{@link cokr.xit.foundation.data.paging.Pageable} </li>
* </ul>
* </li>
* <li>resultType - {@code <select .../>} resultType .
* <ul><li>map</li>
* <li>{@link cokr.xit.foundation.data.paging.Pageable} </li>
* </ul>
* </li>
* </ul>
* <p><b> </b><br />
* map
* <pre>{@code DataObject params = new DataObject()
* .set("pageNum", 1)
* .set("fetchSize", 10);
* List<?> list = aTableMapper.selectXXX(params);
* }</pre>
* QueryRequest
* <pre>{@code QueryRequest req = new QueryRequest();
* req.setPageNum(1)
* req.setFetchSize(10);
* List<?> list = aTableMapper.selectXXX(req);
* }</pre>
* Pageable
* <pre>{@code class PageableObject implements Pageable {
* ....
* };
* PageableObject req = new PageableObject();
* req.setPageNum(1)
* req.setFetchSize(10);
* List<?> list = aTableMapper.selectXXX(req);
* }</pre>
* <p><b> </b><br />
* {@link cokr.xit.foundation.web.AbstractController} <br />
* <code>setPagingInfo(ModelAndView, List, String)</code> ModelAndView .
* <pre>{@code setPagingInfo(new ModelAndView("viewName"), list, "example");}</pre>
*/
package cokr.xit.foundation.data.paging;

@ -0,0 +1,105 @@
/** ,
* <h3></h3>
* <p> ,<br />
* troubleshooting .
* <p>x-base slf4j {@link Log} .<br />
* x-base {@link AbstractComponent} <br />
* {@link AbstractComponent#log()} .
* <h3> </h3>
* x-base .
* <ul><li>{@link Access}</li>
* <li>{@link UserInfo}</li>
* <li>{@link ApplicationContainer}</li>
* </ul>
* Access UserInfo AbstractComponent AbstractServiceBean
* <ul><li>{@link AbstractComponent#currentAccess()}</li>
* <li>{@link AbstractComponent#currentUser()}</li>
* </ul>
* .
* <p>ApplicationContainer .
* <pre>{@code @Resource(name = "applicationContainer")
* private ApplicationContainer applicationContainer;
* }</pre>
* <h3> </h3>
* *.properties key=value <br />
* .
* <p>x-base EgovPropertyService .<br />
* EgovPropertyService spring/context-common.xml .
* <pre>{@code <bean name="propertyService" class="org.egovframe.rte.fdl.property.impl.EgovPropertyServiceImpl" destroy-method="destroy">
* <property name="properties"><!-- -->
* <map>
* <entry key="tempDir" value="D:/temp"/>
*
* <entry key="pageUnit" value="10"/>
* <entry key="pageSize" value="10"/>
* </map>
* </property>
* <property name="extFileName"><!-- -->
* <set>
* <map>
* <entry key="encoding" value="UTF-8"/>
* <entry key="filename" value="classpath*:properties/your-file.properties"/>
* </map>
* <map>
* <entry key="encoding" value="UTF-8"/>
* <entry key="filename" value="classpath*:properties/your-file2.properties"/>
* </map>
* </set>
* </property>
* </bean>
* }</pre>
* .
* <p>x-base AbstractComponent AbstractServiceBean <br />
* {@link AbstractComponent#properties} .
* <h3> </h3>
* <ul><li> .</li>
* <li> .</li>
* <li> .</li>
* <li> <br />
* spring/context-datasource.xml .</li>
* </ul>
* <pre>{@code <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
* <property name="dataSource" ref="dataSource"/>
* </bean>
*
* <tx:advice id="txAdvice" transaction-manager="txManager">
* <tx:attributes>
* <tx:method name="*" rollback-for="Exception"/>
* </tx:attributes>
* </tx:advice>
*
* <aop:config>
* <aop:pointcut id="serviceMethod" expression="execution(* cokr.xit..service.bean..*ServiceBean.*(..))" />
* <aop:pointcut id="requiredTx" expression="execution(* cokr.xit..service.bean..*ServiceBean.*(..))"/>
* <aop:advisor advice-ref="txAdvice" pointcut-ref="requiredTx" />
* </aop:config>
* }</pre>
* <h3>Lombok </h3>
* <ul><li> .</li>
* <li> getter setter
* <ul><li> .</li>
* <li>Lombok .</li>
* <li>Lombok @Getter @Setter .</li>
* </ul>
* </li>
* </ul>
* <h3> </h3>
*
* <h3> </h3>
* {@link ApplicationException} .<br />
* ApplicationException
* <pre>{@code if (result == null)
* throw ApplicationException
* .get(null)
* .setCode("NPE")
* .setMessage("결과값이 없습니다.")
* .info("reason", "알 수 없음"); // 추가 정보 설정
* }</pre>
* ApplicationException
* <pre>{@code try {
* ...
* } catch(Exception e) {
* throw ApplicationException.get(e);
* }}</pre>
*/
package cokr.xit.foundation;

@ -0,0 +1,43 @@
package cokr.xit.foundation.test;
import org.springframework.stereotype.Repository;
import cokr.xit.foundation.component.AbstractDao;
/**JUnit SQL DAO.<br />
* .<br />
* TestDao test.xml.
* @author mjkhan
*/
@Repository("testDao")
public class TestDao extends AbstractDao {
/** INSERT .
* @param sql INSERT SQL
* @return
*/
public int execInsert(String sql) {
return insert("test.insert", params().set("sql", sql));
}
/** UPDATE .
* @param sql UPDATE SQL
* @return
*/
public int execUpdate(String sql) {
return insert("test.update", params().set("sql", sql));
}
/** DELETE .
* @param sql DELETE SQL
* @return
*/
public int execDelete(String sql) {
return insert("test.delete", params().set("sql", sql));
}
/** SQL .
*/
public void commit() {
update("test.commit");
}
}

@ -0,0 +1,60 @@
package cokr.xit.foundation.test;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.annotation.Resource;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import cokr.xit.foundation.AbstractComponent;
import cokr.xit.foundation.UserInfo;
import cokr.xit.foundation.data.DataObject;
/** .<br />
* TestSupport
* <ul><li>JUnit5 </li>
* <li> spring (spring/context-*.xml) </li>
* <li>"test" .</li>
* <li>AbstractComponent .</li>
* </ul>
* <p> src/test/java .
* <p> cokr.xit.example.business.service.BusinessService <br />
* src/test/java cokr.xit.example.business.service <br />
* BusinessServiceTest .
* @author mjkhan
*/
@ExtendWith(SpringExtension.class)
@ContextConfiguration("classpath:spring/context-*.xml")
@ActiveProfiles("test")
public class TestSupport extends AbstractComponent {
@Resource(name="testDao")
protected TestDao testDao;
protected DataObject dataObject() {
return new DataObject();
}
/**user .
* @param user
*/
protected void currentUser(UserInfo user) {
UserInfo.Provider.get().setUserInfo(user);
}
/** SQL , (,) .<br />
* SQL IN (...) .
* @param params
* @return (,) SQL
*/
protected String join(Object... params) {
return Stream.of(params).map(obj -> "'" + obj + "'").collect(Collectors.joining(","));
}
@AfterEach
void tearDown() {}
}

@ -0,0 +1,3 @@
/**JUnit5
*/
package cokr.xit.foundation.test;

@ -0,0 +1,74 @@
package cokr.xit.foundation.util;
import java.security.MessageDigest;
import org.apache.commons.codec.binary.Base64;
import cokr.xit.foundation.AbstractComponent;
/** .
* @author mjkhan
*/
public class CharsEncoder extends AbstractComponent {
private String algorithm;
private boolean plainText;
/** . SHA-256.
* @return
*/
public String getAlgorithm() {
return ifEmpty(algorithm, "SHA-256");
}
/** . SHA-256.
* @param algorithm
*/
public void setAlgorithm(String algorithm) {
this.algorithm = algorithm;
}
/** .
* @param plainText
* <ul><li> true</li>
* <li> false()</li>
* </ul>
*/
public void setPlainText(boolean plainText) {
this.plainText = plainText;
}
/** BASE64 .
* @param rawChars
* @return
*/
public String encode(CharSequence rawChars) {
if (isEmpty(rawChars)) return "";
String str = rawChars.toString();
if (plainText) return str;
try {
MessageDigest md = MessageDigest.getInstance(getAlgorithm());
md.reset();
md.update(str.getBytes());
byte[] hashValue = md.digest(str.getBytes());
return new String(Base64.encodeBase64(hashValue));
} catch (Exception e) {
throw applicationException(e);
}
}
/** .
* @param rawChars
* @param encodedChars
* @return
* <ul><li> true</li>
* <li> false</li>
* </ul>
*/
protected boolean matches(CharSequence rawChars, String encodedChars) {
String encoded = encode(rawChars);
return encoded.equals(encodedChars);
}
}

@ -0,0 +1,25 @@
package cokr.xit.foundation.util;
import java.util.concurrent.ThreadLocalRandom;
/**
* @author mjkhan
*/
public class RandomNumber {
/** 릿 .
* @param digit 릿
* @return 릿
*/
public static final String get(int digit) {
if (digit < 1)
throw new IllegalArgumentException("digit < 1");
ThreadLocalRandom random = ThreadLocalRandom.current();
StringBuilder buff = new StringBuilder();
for (int i = 0; i < digit; ++i) {
buff.append(Integer.toString(random.nextInt(10)));
}
return buff.toString();
}
}

@ -0,0 +1,3 @@
/**
*/
package cokr.xit.foundation.util;

@ -0,0 +1,202 @@
package cokr.xit.foundation.web;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.Collection;
import java.util.List;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.servlet.ModelAndView;
import com.fasterxml.jackson.databind.ObjectMapper;
import cokr.xit.foundation.AbstractComponent;
import cokr.xit.foundation.Access;
import cokr.xit.foundation.component.QueryRequest;
import cokr.xit.foundation.data.paging.BoundedList;
/** MVC .<br />
* .
* <p>AbstractController
* <ul><li>AbstractComponent </li>
* <li>{@link #ajaxRequest() AJAX } </li>
* <li>{@link #jsonResponse() JSON } </li>
* <li>{@link #toJson(Object) JSON } {@link #fromJson(String, Class) } </li>
* <li>{@link #setCollectionInfo(ModelAndView, List, String) List ModelAndView }</li>
* <li>{@link #download(InputStream, String, String, long, String, HttpServletResponse) }</li>
* </ul>
* .
* <p> ' ' + Controller , @Controller .
* <p> @RequestMapping, @PostMapping url .<br/>
* <pre><code> @RequestMapping(name = "홈", value = "index.do")
* public String index() {return "index";}</code></pre>
* <p>
* <ul><li> @RequestMapping</li>
* <li> @PostMapping</li>
* </ul>
* .
* @author mjkhan
*/
public abstract class AbstractController extends AbstractComponent {
@Resource(name="objectMapper")
private ObjectMapper objectMapper;
/** AJAX .
* @return
* <ul><li>AJAX true</li>
* <li> false</li>
* </ul>
*/
protected boolean ajaxRequest() {
return Access.current().isAjaxRequest();
}
/** JSON .
* @return
* <ul><li>JSON true</li>
* <li> false</li>
* </ul>
*/
protected boolean jsonResponse() {
return Access.current().isJsonResponse();
}
/**obj JSON .
* @param obj
* @return JSON
*/
protected String toJson(Object obj) {
try {
return objectMapper.writeValueAsString(obj);
} catch (Exception e) {
throw applicationException(e);
}
}
/**JSON klass .
* @param <T>
* @param content JSON
* @param klass
* @return klass
*/
protected <T> T fromJson(String content, Class<T> klass) {
try {
return objectMapper.readValue(content, klass);
} catch (Exception e) {
throw applicationException(e);
}
}
/**ModelAndView list .<br />
* <code>setCollectionInfo(mav, list, "obj")</code>
* mav .
* <pre><code>{
* "infoPrefix": "obj",
* "objList": list,
* "objStart": list.getStart(),
* "objFetch": list.getFetchSize(),
* "objTotal": list.getTotalSize(),
* }</code></pre>
* @param mav ModelAndView
* @param collection Collection
* @param prefix
* @return ModelAndView
*/
protected ModelAndView setCollectionInfo(ModelAndView mav, Collection<?> collection, String prefix) {
return setCollectionInfo(mav, collection, "infoPrefix", prefix);
}
/**ModelAndView list .<br />
* <code>setCollectionInfo(mav, list, "yourPrefix", "obj")</code>
* mav .
* <pre><code>{
* "yourPrefix": "obj",
* "objList": list,
* "objStart": list.getStart(),
* "objFetch": list.getFetchSize(),
* "objTotal": list.getTotalSize(),
* }</code></pre>
* @param mav ModelAndView
* @param collection Collection
* @param prefixKey
* @param prefix
* @return ModelAndView
*/
protected ModelAndView setCollectionInfo(ModelAndView mav, Collection<?> collection, String prefixKey, String prefix) {
mav.addObject(prefixKey, prefix)
.addObject(prefix + "List", collection)
.addObject(prefix + "Start", 0)
.addObject(prefix + "Fetch", collection.size())
.addObject(prefix + "Total", collection.size());
if (!(collection instanceof BoundedList))
return mav;
BoundedList<?> bounded = (BoundedList<?>)collection;
return mav.addObject(prefix + "Start", bounded.getStart())
.addObject(prefix + "Fetch", bounded.getFetchSize())
.addObject(prefix + "Total", bounded.getTotalSize());
}
protected <T extends QueryRequest> T setFetchSize(T req) {
if (req.getFetchSize() > 0
|| !isEmpty(req.getDownload())) return req;
return req.setFetchSize(properties.getInt("pageSize"));
}
/**InputStream .
* @param input InputStream
* @param contentType . application/octet-stream
* @param filename
* @param length
* @param disposition 'attachment', 'inline'. attachment
* @param hresp HttpServletResponse
* @throws Exception
*/
protected void download(InputStream input, String contentType, String filename, long length, String disposition, HttpServletResponse hresp) throws Exception {
if (input == null) {
hresp.setStatus(HttpServletResponse.SC_NOT_FOUND);
hresp.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
hresp.setCharacterEncoding("UTF-8");
hresp.setContentType(ifEmpty(contentType, "application/octet-stream"));
hresp.setHeader("Content-Disposition", ifEmpty(disposition, "attachment") + "; filename=\"" + URLEncoder.encode(filename, "UTF-8") +"\"");
hresp.setContentLengthLong(length);
FileCopyUtils.copy(input, hresp.getOutputStream());
}
/**file .
* @param file
* @param contentType . application/octet-stream
* @param filename . file .
* @param disposition 'attachment', 'inline'. attachment
* @param hresp HttpServletResponse
* @throws Exception
*/
protected void download(File file, String contentType, String filename, String disposition, HttpServletResponse hresp) throws Exception {
if (file == null) {
download(null, null, null, 0, null, hresp);
return;
}
try (FileInputStream in = new FileInputStream(file)) {
download(in, contentType, ifEmpty(filename, file.getName()), file.length(), disposition, hresp);
}
}
/** .<br />
* tempDir .<br />
* tempDir (java.io.tmpdir) .
* @param path
* @return +
*/
protected String tempPath(String path) {
String dir = ifEmpty(properties.getString("tempDir"), System.getProperty("java.io.tmpdir")).replace("\\", "/");
return dir.endsWith("/") || path.startsWith("/") ? dir + path : dir + "/" + path;
}
}

@ -0,0 +1,49 @@
package cokr.xit.foundation.web;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import cokr.xit.foundation.Access;
/** {@link Access } .<br />
*
* <ul><li> </li>
* <li>릿 "currentAccess" .</li>
* </ul>
* @author mjkhan
*/
public class AccessFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {}
@Override
public void doFilter(ServletRequest sreq, ServletResponse sresp, FilterChain chain) throws IOException, ServletException {
HttpServletRequest hreq = (HttpServletRequest)sreq;
String action = hreq.getRequestURI().replace(hreq.getContextPath(), "");
HttpSession session = hreq.getSession(false);
Access access = new Access()
.setAction(action)
.setNewSession(session == null || session.isNew())
.setMobile(hreq.getHeader("User-Agent").contains("Mobi"))
.setSessionID(session != null ? session.getId() : null)
.setAjaxRequest(hreq.getHeader("X-Requested-With"))
.setJsonResponse(hreq.getHeader("accept"))
.setCurrent();
hreq.setAttribute("currentAccess", access);
chain.doFilter(sreq, sresp);
}
@Override
public void destroy() {}
}

@ -0,0 +1,108 @@
package cokr.xit.foundation.web;
import java.text.SimpleDateFormat;
import java.util.Locale;
import java.util.Map;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.ModelAndView;
import cokr.xit.foundation.Access;
import cokr.xit.foundation.ApplicationContainer;
import cokr.xit.foundation.UserInfo;
import cokr.xit.foundation.component.ServiceRequest;
/** , HttpServletRequest ,
* (:JSP) .
* <ul><li>"applicationContainer" - {@link ApplicationContainer}</li>
* <li>"currentUser" - ({@link UserInfo })</li>
* <li>"currentAccess" - {@link Access }</li>
* </ul>
*
* <p>AccessInitializer .</p>
*/
public class AccessInitializer extends RequestInterceptor {
@Resource(name="applicationContainer")
protected ApplicationContainer applicationContainer;
@Resource(name="localeResolver")
protected LocaleResolver localeResolver;
private String version;
@Override
public boolean preHandle(HttpServletRequest hreq, HttpServletResponse hresp, Object handler) throws Exception {
log().debug("Initializing access information for the current request...");
hreq.setAttribute("applicationContainer", applicationContainer);
setVersion(hreq);
initUserAccess(hreq);
return super.preHandle(hreq, hresp, handler);
}
@Override
public void postHandle(HttpServletRequest hreq, HttpServletResponse hresp, Object handler, ModelAndView mav) throws Exception {
Map<String, Object> model = mav.getModel();
model.entrySet().stream()
.filter(entry -> entry.getValue() instanceof ServiceRequest)
.map(entry -> entry.getKey())
.collect(Collectors.toList())
.forEach(model::remove);
}
/** "ver=yyMMddHHmm" 릿 "ver" .
* @param hreq 릿
*/
protected void setVersion(HttpServletRequest hreq) {
if (isEmpty(version))
version = "ver=" + new SimpleDateFormat("yyMMddHHmm").format(applicationContainer.getStartupDate());
hreq.setAttribute("ver", version);
}
/** 릿 "currentUser" .
* @param hreq
*/
protected void initUserAccess(HttpServletRequest hreq) {
UserInfo currentUser = UserInfo.current();
hreq.setAttribute("currentUser", currentUser);
hreq.setAttribute("production", applicationContainer.isProfileActive("production"));
log().debug("{} accessing the system.", currentUser);
Locale locale = localeResolver.resolveLocale(hreq);
Access.current()
.setIpAddress(getClientAddress(hreq))
.setLocale(locale);
}
private static final String UNKNOWN = "unknown";
private static final String[] HEADERS = {"x-forwarded-for", "X-FORWARDED-FOR", "WL-Proxy-Client-IP", "HTTP_X_FORWARDED_FOR"};
private String getClientAddress(HttpServletRequest hreq) {
for (String header: HEADERS) {
String addr = hreq.getHeader(header);
if (!isEmpty(addr) && !UNKNOWN.equalsIgnoreCase(addr))
return addr;
}
return Access.getClientAddress(hreq.getRemoteAddr(), applicationContainer.getHostAddress());
}
@Override
public void afterCompletion(HttpServletRequest hreq, HttpServletResponse hresp, Object handler, Exception ex) throws Exception {
super.afterCompletion(hreq, hresp, handler, ex);
Access.release();
log().debug("Access information cleared for the current request.");
}
@Override
public void afterConcurrentHandlingStarted(HttpServletRequest hreq, HttpServletResponse hresp, Object handler) throws Exception {
super.afterConcurrentHandlingStarted(hreq, hresp, handler);
Access.release();
log().debug("Access information cleared for the current request.");
}
}

@ -0,0 +1,109 @@
package cokr.xit.foundation.web;
import java.io.PrintWriter;
import java.io.StringWriter;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import cokr.xit.foundation.Access;
import cokr.xit.foundation.ApplicationException;
/** ModelAndView .
* @author mjkhan
*/
@Controller
@ControllerAdvice
public class ExceptionController extends AbstractController {
/** uri .
* @param hreq 릿
* @return uri
*/
protected String getAction(HttpServletRequest hreq) {
return (String)hreq.getAttribute("javax.servlet.forward.request_uri");
}
/**pageNotFound ModelAndView .
* @param hreq 릿
* @return ModelAndView
*/
@RequestMapping("/error/pageNotFound.do")
public ModelAndView pageNotFound(HttpServletRequest hreq) {
return new ModelAndView(ajaxRequest() ? "jsonView" : "error/errorPage")
.addObject("path", getAction(hreq))
.addObject("failed", true)
.addObject("status", 404)
.addObject("message", message("pageNotFound"));
}
/** ModelAndView .
* @param hreq 릿
* @return ModelAndView
*/
@RequestMapping("/error/sessionExpired.do")
public ModelAndView sessionExpired(HttpServletRequest hreq) {
return new ModelAndView(ajaxRequest() ? "jsonView" : "error/errorPage")
.addObject("path", getAction(hreq))
.addObject("failed", true)
.addObject("status", "sessionExpired")
.addObject("message", message("sessionExpired"))
.addObject("home", true);
}
/** ModelAndView .
* @param hreq 릿
* @return ModelAndView
*/
@RequestMapping("/error/accessDenied.do")
public ModelAndView accessDenied(HttpServletRequest hreq) {
return new ModelAndView(ajaxRequest() ? "jsonView" : "error/errorPage")
.addObject("path", Access.current().getAction())
.addObject("failed", true)
.addObject("status", "accessDenied")
.addObject("message", message("accessDenied"));
}
/**ApplicationException ModelAndView .
* @param e ApplicationException
* @return ModelAndView
*/
@ExceptionHandler(ApplicationException.class)
public ModelAndView onException(ApplicationException e) {
return onException((Throwable)e)
.addObject("errorCode", e.getCode());
}
/**Throwable ModelAndView .
* @param e Throwable
* @return ModelAndView
*/
@ExceptionHandler(Throwable.class)
public ModelAndView onException(Throwable e) {
Throwable cause = rootCause(e);
String action = currentAccess().getAction(),
description = cause.getClass().getSimpleName() + " from " + currentAccess(),
stacktrace = getStackTrace(cause);
log().error(description);
log().error(stacktrace);
return new ModelAndView(ajaxRequest() || jsonResponse() ? "jsonView" : "error/errorPage")
.addObject("status", 500)
.addObject("failed", true)
.addObject("description", description)
.addObject("path", action)
.addObject("message", cause.getMessage())
.addObject("stacktrace", stacktrace);
}
private static String getStackTrace(Throwable throwable) {
StringWriter sw = new StringWriter();
throwable.printStackTrace(new PrintWriter(sw, true));
return sw.getBuffer().toString();
}
}

@ -0,0 +1,77 @@
package cokr.xit.foundation.web;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import cokr.xit.foundation.AbstractComponent;
import cokr.xit.foundation.data.DataObject;
import cokr.xit.foundation.data.hierarchy.Hierarchy;
import cokr.xit.foundation.data.hierarchy.HierarchyBuilder;
/** {@code @RequestMapping} .
* @author mjkhan
*/
public class RequestHandlerReader extends AbstractComponent {
/** {@code @RequestMapping} , {"name", "url", "parentID"} .
* @param requestHandlerMappings
* @return {"name", "url", "parentID"}
*/
public List<DataObject> read(RequestMappingHandlerMapping requestHandlerMappings) {
Map<RequestMappingInfo, HandlerMethod> handlers = requestHandlerMappings.getHandlerMethods();
ArrayList<DataObject> nameURLs = new ArrayList<>();
handlers.forEach((info, methods) -> {
String name = blankIfEmpty(info.getName());
if (!isEmpty(name)) {
int pos = name.lastIndexOf("#");
if (pos > -1)
name = name.substring(pos + 1);
}
Object bean = methods.getBean();
for (String url: info.getPatternsCondition().getPatterns()) {
DataObject row = menuItem(name, url);
nameURLs.add(row.set("bean", bean));
}
});
Set<String> parentIDs = nameURLs.stream()
.filter(row -> !isEmpty(row.get("parentID")))
.map(row -> row.string("parentID"))
.collect(Collectors.toSet());
parentIDs.forEach(parentID -> {
nameURLs.add(menuItem(null, parentID));
});
Hierarchy<DataObject> tree = new HierarchyBuilder<DataObject>()
.getID(row -> row.string("url"))
.getParentID(row -> row.string("parentID"))
.atTop(row -> "/".equals(row.string("parentID")))
.addChild((parent, child) -> {
ArrayList<DataObject> children = (ArrayList<DataObject>)parent.get("children");
if (children == null)
parent.put("children", children = new ArrayList<>());
children.add(child);
})
.setElements(nameURLs)
.build();
return tree.topElements();
}
private static DataObject menuItem(String name, String path) {
int pos = Math.max(path.lastIndexOf("/"), 0);
String parentID = ifEmpty(path.substring(0, pos), "/");
return new DataObject()
.set("name", ifEmpty(name, path))
.set("url", path)
.set("parentID", parentID);
}
}

@ -0,0 +1,28 @@
package cokr.xit.foundation.web;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.AsyncHandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import cokr.xit.foundation.AbstractComponent;
/** .
* @author mjkhan
*/
public class RequestInterceptor extends AbstractComponent implements AsyncHandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest hreq, HttpServletResponse hresp, Object handler) throws Exception {
return true;
}
@Override
public void postHandle(HttpServletRequest hreq, HttpServletResponse hresp, Object handler, ModelAndView mav) throws Exception {}
@Override
public void afterCompletion(HttpServletRequest hreq, HttpServletResponse hresp, Object handler, Exception ex) throws Exception {}
@Override
public void afterConcurrentHandlingStarted(HttpServletRequest hreq, HttpServletResponse hresp, Object handler) throws Exception {}
}

@ -0,0 +1,3 @@
/** ,
*/
package cokr.xit.foundation.web;
Loading…
Cancel
Save