コード例 #1
0
ファイル: TimerRunnerAtom.java プロジェクト: OuZhencong/ztask
/**
 * 本原子,每次唤醒,都去运行 schedule, <br>
 * schedule 负责为每个 handle 启动新线程运行,以便本原子运行时间精确
 *
 * @author zozoh([email protected])
 */
public class TimerRunnerAtom extends AbstractAtom {

  private static final Log log = Logs.get();

  @Override
  protected long exec() {
    // 首先以间隔 1000 ms 的时间,自旋等待 schedule 的准备完成
    while (!factory.schedule().isReady() && !factory.schedule().isStop()) {

      if (log.isDebugEnabled()) log.debug("check schedule ...");

      synchronized (factory.schedule()) {
        try {
          factory.schedule().wait(1000);
        } catch (InterruptedException e) {
          throw Lang.wrapThrow(e);
        }
      }
    }

    return factory.schedule().runSlot(Calendar.getInstance(), log);
  }

  public static final String NAME = "SCHD.run";

  @Override
  public String getName() {
    return NAME;
  }
}
コード例 #2
0
/**
 * 统计每天/每小时的独立活跃用户数
 *
 * @author wendal
 */
public class DailyUniqueUsersProcessor extends AbstractProcessor implements RedisKey {

  protected JedisPool pool;

  private static final Log log = Logs.get();

  public void process(ActionContext ac) throws Throwable {
    try {
      if (pool == null) pool = Mvcs.getIoc().get(JedisPool.class);
      int uid = Toolkit.uid();
      if (uid > 0) {
        try (Jedis jedis = pool.getResource()) {
          Pipeline pipe = jedis.pipelined();
          pipe.setbit(RKEY_ONLINE_DAY + Toolkit.today_yyyyMMdd(), uid, true);
          pipe.setbit(RKEY_ONLINE_HOUR + Toolkit.today_yyyyMMddHH(), uid, true);
          pipe.sync();
        }
      }
    } catch (Exception e) {
      if (e instanceof JedisConnectionException) {
        log.debug("jedis is down? ignore error");
      } else {
        log.debug("something wrong? ignore error", e);
      }
    }
    doNext(ac);
  }
}
コード例 #3
0
ファイル: WebLauncher.java プロジェクト: OuZhencong/ztask
/**
 * 一个 Web 服务的启动器
 *
 * @author zozoh([email protected])
 */
public class WebLauncher {

  private static final Log log = Logs.get();

  /**
   * 启动的主函数,接受一个参数,为 web 服务器的配置文件路径。如果没有这个参数,默认在 classpath 下寻找 "web.properties" 文件。
   *
   * <p>这个文件遵循 Nutz 多行属性文件规范,同时必须具备如下的键:
   *
   * <ul>
   *   <li>"app-root" - 应用的根路径,比如 "~/workspace/git/danoo/strato/domain/ROOT"
   *   <li>"app-port" - 应用监听的端口,比如 8080
   *   <li>"app-rs" - 应用静态资源的地址前缀,比如 "http://localhost/strato",或者 "/rs" 等
   *   <li>"app-classpath" - 应用的类路径,可多行
   *   <li>"admin-port" - 应用的管理端口,比如 8081
   * </ul>
   *
   * 这个文件的例子,请参看源码 conf 目录下的 web.properties
   *
   * @param args 接受一个参数作为 web 服务器的配置文件路径
   */
  public static void main(String[] args) {
    String path = Strings.sBlank(Lang.first(args), Webs.CONF_PATH);

    log.infof("launch by '%s'", path);

    final WebServer server = new WebServer(new WebConfig(path));

    server.run();

    log.info("Server is down!");
  }
}
コード例 #4
0
@IocBean
public class SeckenAuthService {

  private static Log log = Logs.get();

  @Inject Dao dao;

  @Inject Secken secken;

  @OnEvent("get_auth_qr")
  public void getAuthQr(SocketIOClient client, Object data, AckRequest ackRequest) {
    NutMap re = new NutMap();
    try {
      // TODO 可配置
      SeckenResp resp =
          secken
              .getAuth(1, "https://nutz.cn/secken/callback/" + R.UU32(client.getSessionId()))
              .check();
      String url = resp.qrcode_url();
      re.put("ok", true);
      re.put("url", url);
    } catch (Exception e) {
      log.debug("获取洋葱授权二维码识别", e);
      re.put("msg", "获取洋葱授权二维码识别");
    }
    client.sendEvent("new_auth_qr", re);
  }

  @OnConnect
  public void welcome(SocketIOClient client) {
    client.sendEvent("login", "");
  }
}
コード例 #5
0
/**
 * @author Wizzer.cn
 * @time 2012-9-13 上午10:54:04
 */
public class UserLoginFilter implements ActionFilter {
  private final Log log = Logs.get();

  @Override
  public View match(ActionContext context) {
    Sys_user user = (Sys_user) context.getRequest().getSession().getAttribute("userSession");
    if (user == null) {
      ServerRedirectView view = new ServerRedirectView("/include/error/nologin.jsp");
      return view;
    }

    Hashtable<String, String> btnmap = user.getBtnmap();
    if (btnmap != null) {
      String initBtn = "";
      String bts =
          btnmap.get(
              Strings.sNull(
                  context.getRequest().getRequestURI().replace(Globals.APP_BASE_NAME, "")));
      if (bts != null && bts.indexOf(",") > 0) {
        String[] tb = StringUtils.split(bts, ",");
        for (int i = 0; i < tb.length; i++) {
          initBtn += "$Z(\"" + tb[i] + "\").enable();\r\n";
        }
      }
      context.getRequest().setAttribute("initBtn", initBtn);
    }
    context.getRequest().setAttribute("curuser", user);
    return null;
  }
}
コード例 #6
0
ファイル: EjectByGetter.java プロジェクト: huangleisir/nutz
public class EjectByGetter implements Ejecting {

  private static final Log log = Logs.get();

  private Method getter;

  public EjectByGetter(Method getter) {
    this.getter = getter;
  }

  public Object eject(Object obj) {
    try {
      return null == obj ? null : getter.invoke(obj);
    } catch (InvocationTargetException e) {
      throw new FailToGetValueException("getter=" + getter, e);
    } catch (Exception e) {
      if (log.isInfoEnabled()) log.info("Fail to value by getter", e);
      throw Lang.makeThrow(
          "Fail to invoke getter %s.'%s()' because [%s]: %s",
          getter.getDeclaringClass().getName(),
          getter.getName(),
          Lang.unwrapThrow(e),
          Lang.unwrapThrow(e).getMessage());
    }
  }
}
コード例 #7
0
ファイル: MainSetup.java プロジェクト: belialofking/tool
 public void destroy(NutConfig nc) {
   // Trace.
   Trace.removeReceiver(receiver);
   try {
     receiver.close();
   } catch (IOException ex) {
     Logs.get().error("MainSetup close receiver error", ex);
   }
 }
コード例 #8
0
ファイル: WXActionHelper.java プロジェクト: gongrui/VMall
  public NutMap wx_minfo(String info, HttpServletRequest req) throws Exception {
    String uri = myWxApi.getCompleteUri(req); // 获取完整uri,否则jsticket无法使用
    Logs.get().debugf("request url=%s", uri);

    String decinfo = BlueDes.decrypt(info);
    HashMap<String, String> minfo = Json.fromJson(HashMap.class, decinfo);

    return wx_init(uri, minfo);
  }
コード例 #9
0
ファイル: Tmp1Module.java プロジェクト: howe/kongchong
@At("/Tmp1")
@IocBean(fields = {"dao"})
public class Tmp1Module extends EntityService<Tmp1> {

  private static final Log log = Logs.get();

  @At
  public Object list(@Param("page") int page, @Param("rows") int rows) {
    if (rows < 1) rows = 10;
    Pager pager = dao().createPager(page, rows);
    List<Tmp1> list = dao().query(Tmp1.class, null, pager);
    Map<String, Object> map = new HashMap<String, Object>();
    if (pager != null) {
      pager.setRecordCount(dao().count(Tmp1.class));
      map.put("pager", pager);
    }
    map.put("list", list);
    return map;
  }

  @At
  public boolean add(@Param("..") Tmp1 obj) {
    try {
      dao().insert(obj);
      return true;
    } catch (Throwable e) {
      if (log.isDebugEnabled()) log.debug("E!!", e);
      return false;
    }
  }

  @At
  public boolean delete(@Param("..") Tmp1 obj) {
    try {
      dao().delete(obj);
      return true;
    } catch (Throwable e) {
      if (log.isDebugEnabled()) log.debug("E!!", e);
      return false;
    }
  }

  @At
  public boolean update(@Param("..") Tmp1 obj) {
    try {
      dao().update(obj);
      return true;
    } catch (Throwable e) {
      if (log.isDebugEnabled()) log.debug("E!!", e);
      return false;
    }
  }
}
コード例 #10
0
/**
 * 处理跨屏登陆的入口授权
 *
 * @author wendal
 */
public class CrossScreenAuthentication extends FormAuthenticationFilter {

  private static final Log log = Logs.get();

  protected long timeout = 60;

  protected SysLogService sysLogService;

  public boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue)
      throws Exception {
    HttpServletRequest req = (HttpServletRequest) request;
    HttpServletResponse resp = (HttpServletResponse) response;
    if ("GET".equals(req.getMethod()) && !Strings.isBlank(req.getParameter("token"))) {
      String token = req.getParameter("token");
      try {
        token = Toolkit._3DES_decode(CrossScreen.csKEY, Toolkit.hexstr2bytearray(token));
        NutMap map = Json.fromJson(NutMap.class, token);
        Long t = map.getLong("t", -1);
        if (System.currentTimeMillis() - t > timeout * 1000) {
          resp.sendError(403); // TODO 提示token已经过期
          return false;
        }
        Integer uid = (Integer) map.get("uid");
        if (uid != null) {
          // 有登陆用户
          Toolkit.doLogin(new CrossScreenUserToken(uid), uid);
          if (sysLogService == null) {
            try {
              sysLogService = Mvcs.ctx().getDefaultIoc().get(SysLogService.class);
            } catch (Throwable e) {
            }
          }
          sysLogService.async(SysLog.c("method", "用户登陆", null, uid, "用户通过跨屏二维码登陆"));
        }
        resp.sendRedirect(map.getString("url"));
        return false;
      } catch (Exception e) {
        log.debug("bad token?", e);
        resp.sendError(502);
        return false;
      }
    } else {
      resp.sendError(403);
      return false;
    }
  }

  public void setTimeout(long timeout) {
    this.timeout = timeout;
  }
}
コード例 #11
0
ファイル: UserAPITest.java プロジェクト: Rekoe/mpsdk4j
/**
 * UserAPI 测试
 *
 * @author 凡梦星尘([email protected])
 * @since 2.0
 */
@FixMethodOrder(MethodSorters.JVM)
public class UserAPITest extends APITestSupport {

  private static final Log log = Logs.get();

  private UserAPI ua;

  @Before
  public void init() {
    log.info("====== UserAPITest ====== ");
    super.init();
    ua = WechatAPIImpl.create(mpAct);
  }

  @Test
  public void testGetFollowerList() {
    log.info("====== UserAPI#getFollowerList ====== ");
    FollowList fl = ua.getFollowerList(null);
    assertNotNull(fl);
    log.info(fl);
  }

  @Test
  public void testGetFollower() {
    log.info("====== UserAPI#getFollower ====== ");
    Follower f = ua.getFollower(openId, null);
    assertNotNull(f);
    log.info(f);
  }

  @Test
  public void testUpdateRemark() {
    log.info("====== UserAPI#updateRemark ====== ");
    boolean flag = ua.updateRemark(openId, "Youself");
    assertTrue(flag);
    log.info(flag);
  }

  @Test
  public void testGetFollowers() {
    log.info("====== UserAPI#getFollowers ====== ");
    List<Follower2> getfs = new ArrayList<Follower2>();
    getfs.add(new Follower2(openId));
    getfs.add(new Follower2(_cr.get("openId2")));

    List<Follower> fs = ua.getFollowers(getfs);
    assertNotNull(fs);
    assertEquals(2, fs.size());
    log.info(fs);
  }
}
コード例 #12
0
public class BeetlViewMaker2 extends BeetlViewMaker {

  public static final Log log = Logs.get();

  public BeetlViewMaker2() throws IOException {
    super();
  }

  public void init() {
    try {
      super.init();
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
    // 添加全局变量
    Map<String, Object> share = groupTemplate.getSharedVars();
    if (share == null) {
      share = new NutMap();
      groupTemplate.setSharedVars(share);
    }
    Ioc ioc = Mvcs.getIoc();
    share.put("ioc", ioc);
    PropertiesProxy conf = ioc.get(PropertiesProxy.class, "conf");
    share.put("conf", conf.toMap());

    if (!conf.getBoolean("cdn.enable", false) || Strings.isBlank(conf.get("cdn.urlbase"))) {
      share.put("cdnbase", "");
    } else {
      share.put("cdnbase", conf.get("cdn.urlbase"));
      MarkdownFunction.cdnbase = conf.get("cdn.urlbase");
    }
  }

  @Override
  public View make(Ioc ioc, String type, String value) {
    if ("beetl".equals(type))
      return new BeetlView(render, value) {
        @Override
        public void render(HttpServletRequest req, HttpServletResponse resp, Object obj)
            throws Throwable {
          Stopwatch sw = Stopwatch.begin();
          super.render(req, resp, obj);
          sw.stop();
          log.debug("render time=" + sw.getDuration());
        }
      };
    return null;
  }
}
コード例 #13
0
/**
 * 检验优惠券和活动是否有效的任务
 *
 * @author 凡梦星尘([email protected])
 * @since 2015/5/4
 * @version 1.0.0
 */
@IocBean
public class CheckValidJob implements Job {

  private static final Log log = Logs.get();

  @Inject private TrailService trailService;
  @Inject private CouponService couponService;

  @Override
  public void execute(JobExecutionContext jec) throws JobExecutionException {

    trailService.makeInvalid();
    couponService.makeInvalid();
  }
}
コード例 #14
0
ファイル: TestTask.java プロジェクト: ycmag/NUTZ-ONEKEY
/**
 * @author Kerbores([email protected])
 * @project thunder-web
 * @file Test.java
 * @description 测试任务
 * @time 2016年3月8日 上午10:51:26
 */
@IocBean
@Scheduled(cron = "0 */45 * * * ? ")
public class TestTask implements Job {
  private static Log LOG = Logs.getLog(TestTask.class);

  /*
   * (non-Javadoc)
   *
   * @see org.quartz.Job#execute(org.quartz.JobExecutionContext)
   */
  @Override
  public void execute(JobExecutionContext arg0) throws JobExecutionException {
    LOG.debug("running...");
  }
}
コード例 #15
0
/** @author <a href="mailto:[email protected]">Json Shen</a> 2010-7-18 下午02:44:08 */
public class MyUrlMapImpl extends UrlMappingImpl {

  private static final Log log = Logs.getLog(MyUrlMapImpl.class);

  /** 添加URL时初始化权限 */
  @Override
  public void add(ActionChainMaker maker, ActionInfo ai, NutConfig config) {
    super.add(maker, ai, config);
    Method method = ai.getMethod();
    Authority a = method.getAnnotation(Authority.class);
    if (null == a) {
      return;
    }
    String id = a.value();
    String module = a.module();
    String desc = a.desc();
    boolean isDefault = a.isDefault();

    // 在这里可以把权限写入数据库以及其它操作,此处为运行demo简单只写日志.
    log.infof("AuthID=%s Module=%s Default=%s Desc=%s", id, module, isDefault, desc);
  }
}
コード例 #16
0
public class SystemSetup implements Setup {

  private static final Log log = Logs.get();

  private static final int INTERVAL = 30 * 1000; // 在线用户的未读消息刷新间隔时间 30秒

  private static Timer timer = new Timer("schedule Runner"); // 建立调度任务线程

  @Override
  public void init(NutConfig config) {
    Ioc ioc = config.getIoc();

    final Dao dao = ioc.get(null, "dao");

    timer.schedule(
        new TimerTask() {
          @Override
          public void run() {}
        },
        1000,
        INTERVAL);
    if (log.isInfoEnabled()) {
      log.info("系统初始化完毕");
    }
  }

  @Override
  public void destroy(NutConfig config) {
    if (timer != null) {
      timer.cancel();
      timer = null;
      if (log.isInfoEnabled()) {
        log.info("schedule Runner 已关闭");
      }
    }
  }
}
コード例 #17
0
ファイル: EmailServiceImpl.java プロジェクト: kangqbing/koo
@ZBusConsumer(mq = "email")
@IocBean(name = "emailService")
public class EmailServiceImpl implements EmailService, MessageHandler {

  private static final Log log = Logs.get();

  @Inject("refer:$ioc")
  protected Ioc ioc;

  public boolean send(String to, String subject, String html) {
    try {
      HtmlEmail email = ioc.get(HtmlEmail.class);
      email.setSubject(subject);
      email.setHtmlMsg(html);
      email.addTo(to);
      email.buildMimeMessage();
      email.sendMimeMessage();
      return true;
    } catch (Throwable e) {
      log.info("send email fail", e);
      return false;
    }
  }

  public boolean isSupport(Object event) {
    return event instanceof Email;
  }

  public void handle(Message msg, Session sess) throws IOException {
    Email email = Json.fromJson(Email.class, msg.getBodyString());
    try {
      email.send();
    } catch (EmailException e) {
      e.printStackTrace();
    }
  }
}
コード例 #18
0
ファイル: Castors.java プロジェクト: newisso/nutz
/**
 * 一个创建 Castor 的工厂类。它的使用方式是:
 *
 * <pre>
 * Castors.me().cast(obj, fromType, toType);
 * </pre>
 *
 * @author zozoh([email protected])
 * @author Wendal([email protected])
 */
public class Castors {

  private static final Log log = Logs.get();

  /** @return 单例 */
  public static Castors me() {
    return one;
  }

  /** @return 一个新的 Castors 实例 */
  public static Castors create() {
    return new Castors();
  }

  /** 如何抽取对象的类型级别 */
  private TypeExtractor extractor;

  /** Castor 的配置 */
  private Object setting;

  /**
   * 设置转换的配置
   *
   * <p>配置对象所有的共有方法都会被遍历。只要这个方法有一个且只有一个参数,并且该参数 是一个 org.nutz.castor.Castor 接口的实现类。那么就会被认为是对该种 Castor
   * 的一个 配置。
   *
   * <p>当初始化这个 Castor 之前,会用这个方法来设置一下你的 Castor (如果你的 Castor 需要配置的话)
   *
   * @param obj 配置对象。可以是任意的 Java 对象。
   */
  public synchronized Castors setSetting(Object obj) {
    if (obj != null) {
      setting = obj;
      this.reload();
    }
    return this;
  }

  /**
   * 设置自定义的对象类型提取器逻辑
   *
   * @param te 类型提取器
   */
  public synchronized Castors setTypeExtractor(TypeExtractor te) {
    extractor = te;
    return this;
  }

  private Castors() {
    setting = new DefaultCastorSetting();
    reload();
  }

  private void reload() {
    HashMap<Class<?>, Method> settingMap = new HashMap<Class<?>, Method>();
    for (Method m1 : setting.getClass().getMethods()) {
      Class<?>[] pts = m1.getParameterTypes();
      if (pts.length == 1 && Castor.class.isAssignableFrom(pts[0])) settingMap.put(pts[0], m1);
    }

    this.map = new HashMap<Integer, Castor<?, ?>>();
    ArrayList<Class<?>> classes = new ArrayList<Class<?>>();
    classes.addAll(defaultCastorList);
    for (Class<?> klass : classes) {
      try {
        if (Modifier.isAbstract(klass.getModifiers())) continue;
        if (!Castor.class.isAssignableFrom(klass)) continue;
        fillMap(klass, settingMap);
      } catch (Throwable e) {
        if (log.isWarnEnabled())
          log.warnf("Fail to create castor [%s] because: %s", klass, e.getMessage());
      }
    }
    if (log.isDebugEnabled()) log.debugf("Using %s castor for Castors", map.size());
  }

  public void addCastor(Class<?> klass) {
    try {
      fillMap(klass, new HashMap<Class<?>, Method>());
    } catch (Throwable e) {
      throw Lang.wrapThrow(Lang.unwrapThrow(e));
    }
  }

  /**
   * 填充 map .<br>
   * 在map中使用hash值来做为key来进行存储
   *
   * @param klass
   * @param settingMap
   * @throws InstantiationException
   * @throws IllegalAccessException
   * @throws IllegalArgumentException
   * @throws InvocationTargetException
   */
  private void fillMap(Class<?> klass, HashMap<Class<?>, Method> settingMap)
      throws InstantiationException, IllegalAccessException, IllegalArgumentException,
          InvocationTargetException {
    Castor<?, ?> castor = (Castor<?, ?>) klass.newInstance();
    if (!map.containsKey(castor.hashCode())) {
      map.put(castor.hashCode(), castor);
    }
    Method m = settingMap.get(castor.getClass());
    if (null == m) {
      for (Entry<Class<?>, Method> entry : settingMap.entrySet()) {
        Class<?> cc = entry.getKey();
        if (cc.isAssignableFrom(klass)) {
          m = settingMap.get(cc);
          break;
        }
      }
    }
    if (null != m) m.invoke(setting, castor);
  }

  /** First index is "from" (source) The second index is "to" (target) */
  //    private Map<String, Map<String, Castor<?, ?>>> map;
  private Map<Integer, Castor<?, ?>> map;

  /**
   * 转换一个 POJO 从一个指定的类型到另外的类型
   *
   * @param src 源对象
   * @param fromType 源对象类型
   * @param toType 目标类型
   * @param args 转换时参数。有些 Castor 可能需要这个参数,比如 Array2Map
   * @return 目标对象
   * @throws FailToCastObjectException 如果没有找到转换器,或者转换失败
   */
  @SuppressWarnings({"unchecked", "rawtypes"})
  public <F, T> T cast(Object src, Class<F> fromType, Class<T> toType, String... args)
      throws FailToCastObjectException {
    if (null == src) {
      // 原生数据的默认值
      if (toType.isPrimitive()) {
        if (toType == int.class) return (T) Integer.valueOf(0);
        else if (toType == long.class) return (T) Long.valueOf(0L);
        else if (toType == byte.class) return (T) Byte.valueOf((byte) 0);
        else if (toType == short.class) return (T) Short.valueOf((short) 0);
        else if (toType == float.class) return (T) Float.valueOf(.0f);
        else if (toType == double.class) return (T) Double.valueOf(.0);
        else if (toType == boolean.class) return (T) Boolean.FALSE;
        else if (toType == char.class) return (T) Character.valueOf(' ');
        throw Lang.impossible();
      }
      // 是对象,直接返回 null
      return null;
    }
    if (fromType == toType || toType == null || fromType == null) return (T) src;
    if (fromType.getName().equals(toType.getName())) return (T) src;
    if (toType.isAssignableFrom(fromType)) return (T) src;
    Mirror<?> from = Mirror.me(fromType, extractor);
    if (from.canCastToDirectly(toType)) // Use language built-in cases
    return (T) src;
    Castor c = find(from, toType);
    if (null == c)
      throw new FailToCastObjectException(
          String.format(
              "Can not find castor for '%s'=>'%s' in (%d) because:\n%s",
              fromType.getName(), toType.getName(), map.size(), "Fail to find matched castor"));
    try {
      return (T) c.cast(src, toType, args);
    } catch (FailToCastObjectException e) {
      throw e;
    } catch (Exception e) {
      throw new FailToCastObjectException(
          String.format(
              "Fail to cast from <%s> to <%s> for {%s} because:\n%s:%s",
              fromType.getName(),
              toType.getName(),
              src,
              e.getClass().getSimpleName(),
              e.getMessage()),
          Lang.unwrapThrow(e));
    }
  }

  /**
   * 获取一个转换器
   *
   * @param from 源类型
   * @param to 目标类型
   * @return 转换器
   */
  public <F, T> Castor<F, T> find(Class<F> from, Class<T> to) {
    return find(Mirror.me(from), to);
  }

  @SuppressWarnings("unchecked")
  private <F, T> Castor<F, T> find(Mirror<F> from, Class<T> toType) {
    Mirror<T> to = Mirror.me(toType, extractor);
    Class<?>[] fets = from.extractTypes();
    Class<?>[] tets = to.extractTypes();
    for (Class<?> ft : fets) {
      for (Class<?> tt : tets) {
        if (map.containsKey(Castor.fetchHash(ft, tt))) {
          return (Castor<F, T>) map.get(Castor.fetchHash(ft, tt));
        }
      }
    }
    return null;
  }

  /**
   * 转换一个 POJO 到另外的类型
   *
   * @param src 源对象
   * @param toType 目标类型
   * @return 目标对象
   * @throws FailToCastObjectException 如果没有找到转换器,或者转换失败
   */
  public <T> T castTo(Object src, Class<T> toType) throws FailToCastObjectException {
    return cast(src, null == src ? null : src.getClass(), toType);
  }

  /**
   * 判断一个类型是否可以被转换成另外一个类型
   *
   * <p>判断的依据就是看是否可以直接被转型,以及能不能找到一个专有的转换器
   *
   * @param fromType 起始类型
   * @param toType 目标类型
   * @return 是否可以转换
   */
  public boolean canCast(Class<?> fromType, Class<?> toType) {
    if (Mirror.me(fromType).canCastToDirectly(toType)) return true;
    Castor<?, ?> castor = this.find(fromType, toType);
    return !(castor instanceof Object2Object);
  }

  /**
   * 将一个 POJO 转换成字符串
   *
   * @param src 源对象
   * @return 字符串
   */
  public String castToString(Object src) {
    try {
      return castTo(src, String.class);
    } catch (FailToCastObjectException e) {
      return String.valueOf(src);
    }
  }

  private static List<Class<?>> defaultCastorList = new ArrayList<Class<?>>(100);

  static {
    defaultCastorList.add(org.nutz.castor.castor.String2Character.class);
    defaultCastorList.add(org.nutz.castor.castor.Calendar2String.class);
    defaultCastorList.add(org.nutz.castor.castor.Calendar2Timestamp.class);
    defaultCastorList.add(org.nutz.castor.castor.Collection2Collection.class);
    defaultCastorList.add(org.nutz.castor.castor.Collection2Object.class);
    defaultCastorList.add(org.nutz.castor.castor.File2String.class);
    defaultCastorList.add(org.nutz.castor.castor.String2Timestamp.class);
    defaultCastorList.add(org.nutz.castor.castor.Map2Object.class);
    defaultCastorList.add(org.nutz.castor.castor.Datetime2String.class);
    defaultCastorList.add(org.nutz.castor.castor.Array2String.class);
    defaultCastorList.add(org.nutz.castor.castor.String2SqlTime.class);
    defaultCastorList.add(org.nutz.castor.castor.Number2Calendar.class);
    defaultCastorList.add(org.nutz.castor.castor.SqlDate2Timestamp.class);
    defaultCastorList.add(org.nutz.castor.castor.Object2Mirror.class);
    defaultCastorList.add(org.nutz.castor.castor.String2Collection.class);
    defaultCastorList.add(org.nutz.castor.castor.Datetime2Calendar.class);
    defaultCastorList.add(org.nutz.castor.castor.Class2String.class);
    defaultCastorList.add(org.nutz.castor.castor.Number2String.class);
    defaultCastorList.add(org.nutz.castor.castor.Number2Enum.class);
    defaultCastorList.add(org.nutz.castor.castor.Array2Object.class);
    defaultCastorList.add(org.nutz.castor.castor.Timestamp2Calendar.class);
    defaultCastorList.add(org.nutz.castor.castor.Timestamp2String.class);
    defaultCastorList.add(org.nutz.castor.castor.Datetime2SqlTime.class);
    defaultCastorList.add(org.nutz.castor.castor.TimeZone2String.class);
    defaultCastorList.add(org.nutz.castor.castor.String2Boolean.class);
    defaultCastorList.add(org.nutz.castor.castor.Datetime2SqlDate.class);
    defaultCastorList.add(org.nutz.castor.castor.Object2List.class);
    defaultCastorList.add(org.nutz.castor.castor.SqlDate2String.class);
    defaultCastorList.add(org.nutz.castor.castor.Timestamp2SqlDate.class);
    defaultCastorList.add(org.nutz.castor.castor.Map2String.class);
    defaultCastorList.add(org.nutz.castor.castor.DateTimeCastor.class);
    defaultCastorList.add(org.nutz.castor.castor.Boolean2String.class);
    defaultCastorList.add(org.nutz.castor.castor.String2Class.class);
    defaultCastorList.add(org.nutz.castor.castor.String2Pattern.class);
    defaultCastorList.add(org.nutz.castor.castor.String2Map.class);
    defaultCastorList.add(org.nutz.castor.castor.Mirror2Class.class);
    defaultCastorList.add(org.nutz.castor.castor.SqlTime2String.class);
    defaultCastorList.add(org.nutz.castor.castor.Object2Object.class);
    defaultCastorList.add(org.nutz.castor.castor.String2TimeZone.class);
    defaultCastorList.add(org.nutz.castor.castor.Character2Number.class);
    defaultCastorList.add(org.nutz.castor.castor.String2Number.class);
    defaultCastorList.add(org.nutz.castor.castor.Number2Boolean.class);
    defaultCastorList.add(org.nutz.castor.castor.Timestamp2SqlTime.class);
    defaultCastorList.add(org.nutz.castor.castor.Timestamp2Long.class);
    defaultCastorList.add(org.nutz.castor.castor.String2Calendar.class);
    defaultCastorList.add(org.nutz.castor.castor.String2Email.class);
    defaultCastorList.add(org.nutz.castor.castor.Calendar2Datetime.class);
    defaultCastorList.add(org.nutz.castor.castor.Enum2String.class);
    defaultCastorList.add(org.nutz.castor.castor.Collection2Map.class);
    defaultCastorList.add(org.nutz.castor.castor.Array2Array.class);
    defaultCastorList.add(org.nutz.castor.castor.Number2Datetime.class);
    defaultCastorList.add(org.nutz.castor.castor.Map2Array.class);
    defaultCastorList.add(org.nutz.castor.castor.Array2Collection.class);
    defaultCastorList.add(org.nutz.castor.castor.String2Set.class);
    defaultCastorList.add(org.nutz.castor.castor.String2Mirror.class);
    defaultCastorList.add(org.nutz.castor.castor.Mirror2String.class);
    defaultCastorList.add(org.nutz.castor.castor.SqlTime2Timestamp.class);
    defaultCastorList.add(org.nutz.castor.castor.Object2Class.class);
    defaultCastorList.add(org.nutz.castor.castor.Object2Map.class);
    defaultCastorList.add(org.nutz.castor.castor.String2File.class);
    defaultCastorList.add(org.nutz.castor.castor.Boolean2Number.class);
    defaultCastorList.add(org.nutz.castor.castor.Map2Collection.class);
    defaultCastorList.add(org.nutz.castor.castor.String2SqlDate.class);
    defaultCastorList.add(org.nutz.castor.castor.String2Array.class);
    defaultCastorList.add(org.nutz.castor.castor.String2Object.class);
    defaultCastorList.add(org.nutz.castor.castor.Number2Number.class);
    defaultCastorList.add(org.nutz.castor.castor.Class2Mirror.class);
    defaultCastorList.add(org.nutz.castor.castor.String2Datetime.class);
    defaultCastorList.add(org.nutz.castor.castor.Calendar2Long.class);
    defaultCastorList.add(org.nutz.castor.castor.Number2Character.class);
    defaultCastorList.add(org.nutz.castor.castor.Collection2String.class);
    defaultCastorList.add(org.nutz.castor.castor.Datetime2Long.class);
    defaultCastorList.add(org.nutz.castor.castor.Array2Map.class);
    defaultCastorList.add(org.nutz.castor.castor.Number2Timestamp.class);
    defaultCastorList.add(org.nutz.castor.castor.Collection2Array.class);
    defaultCastorList.add(org.nutz.castor.castor.Enum2Number.class);
    defaultCastorList.add(org.nutz.castor.castor.Object2String.class);
    defaultCastorList.add(org.nutz.castor.castor.Timestamp2Datetime.class);
    defaultCastorList.add(org.nutz.castor.castor.Datetime2Timpestamp.class);
    defaultCastorList.add(org.nutz.castor.castor.Map2Enum.class);
    defaultCastorList.add(org.nutz.castor.castor.String2Enum.class);
  }

  private static Castors one = new Castors();
}
コード例 #19
0
ファイル: RoleAction.java プロジェクト: dalinhuang/shop-1
/**
 * 用户权限模块,菜单管理控制器类
 *
 * @author 刘立立
 */
@IocBean
public class RoleAction {

  private static final Log log = Logs.get();

  @Inject("refer:roleServiceImpl")
  public RoleServiceImpl roleService;

  @Inject("refer:menusServiceImpl")
  public MenusServiceImpl menusService;

  /**
   * 获取所有角色信息
   *
   * @param request
   * @param response
   * @return
   */
  // @RequestMapping(value = "queryAllRoleList", method = { RequestMethod.POST })
  public String queryAllRoleList(HttpServletRequest request, HttpServletResponse response) {
    int page = Integer.parseInt(request.getParameter("page")); // 当前页数
    int rows = Integer.parseInt(request.getParameter("rows")); // 每页多少行
    int startNum = page * rows - rows; // 分页查询开始位置
    String roleJsonStr = "";
    Datagrid datagrid = new Datagrid();
    int roleTotalCount = roleService.queryRoleTotalCount(); // 统计角色数量
    List<Role> roleList = roleService.quryAllRoleList(startNum, rows); // 查询角色列表
    datagrid.setRows(roleList);
    datagrid.setTotal(roleTotalCount);
    try {
      // 将查询的角色集合list转换成json格式字符串
      roleJsonStr = Json.toJson(datagrid); // JsonUtils.objectToJackson(datagrid, Datagrid.class);
      PrintWriter out = response.getWriter();
      out.print(roleJsonStr);
      out.flush();
      out.close();
      request.setAttribute("roleJsonStr", roleJsonStr);
    } catch (Exception e) {
      log.error("处理json数据报错:" + e.getStackTrace());
    }
    log.info(roleJsonStr);

    return null;
  }

  /**
   * 新增角色
   *
   * @param request
   * @param response
   * @return
   */
  // @RequestMapping(value = "saveRole", method = { RequestMethod.POST })
  public String saveRole(
      HttpServletRequest request, HttpServletResponse response, Role role, String selectAuthIds) {
    String msg = "";
    try {
      roleService.saveRole(request, role, selectAuthIds); // 保存角色
      msg = "1"; // 保存角色成功
    } catch (Exception e) {
      msg = "0"; // 保存角色失败
      log.error("保存角色失败:" + e.getStackTrace());
    }
    // ResponseUtils.renderText(response, msg);
    return null;
  }
  /**
   * 通过id获取角色
   *
   * @param request
   * @param id
   * @return
   */
  // @RequestMapping(value = "getRoleById", method = { RequestMethod.GET })
  public String getRoleById(HttpServletRequest request, String id) {
    Role role = roleService.getRoleById(id);
    request.setAttribute("role", role);
    return "role/role-input";
  }
  /**
   * @param request
   * @param id
   * @return
   */
  // @RequestMapping(value = "getRoleByCode", method = { RequestMethod.GET })
  public String getRoleByCode(HttpServletRequest request, String id) {
    Role role = roleService.getRoleById(id);
    request.setAttribute("role", role);
    return "role/roleDetails";
  }
  /**
   * 删除角色-支持批量删除
   *
   * @param response
   * @param ids
   * @return
   */
  // @RequestMapping(value = "deleteRoles", method = { RequestMethod.GET })
  public String deleteRoles(HttpServletResponse response, String ids) {
    String msg = "";
    try {
      roleService.deleteRoles(ids);
      msg = "1";
    } catch (Exception e) {
      msg = "0";
      log.error("删除角色失败:" + e.getStackTrace());
    }
    // ResponseUtils.renderText(response, msg);
    return null;
  }
  /**
   * 根据菜单名称获取菜单
   *
   * @param response
   * @param roleName
   * @return
   */
  // @RequestMapping(value="getRoleByRoleName",method={RequestMethod.POST})
  public String getRoleByRoleName(
      HttpServletRequest request, HttpServletResponse response, String roleName) {
    int page = Integer.parseInt(request.getParameter("page")); // 当前页数
    int rows = Integer.parseInt(request.getParameter("rows")); // 每页多少行
    int startNum = page * rows - rows; // 分页查询开始位置

    List<Role> roles = roleService.getRoleByRoleName(roleName, startNum, rows);
    int rolesTotalCountByRoleName = roleService.getRolesTotalCountByRoleName(roleName);
    Datagrid datagrid = new Datagrid();
    datagrid.setRows(roles);
    datagrid.setTotal(rolesTotalCountByRoleName);
    String rolesJsonStr = "";
    try {
      rolesJsonStr =
          Json.toJson(
              datagrid); // JsonUtils.objectToJackson(datagrid, Datagrid.class);// 将对象转换成json字符串
      PrintWriter out = response.getWriter();
      out.print(rolesJsonStr);
      out.flush();
      out.close();
    } catch (Exception e) {
      log.error("处理json数据报错:" + e.getStackTrace());
    }
    return null;
  }

  /**
   * 加载权限树
   *
   * @param request
   * @param response
   * @return
   */
  // @RequestMapping(value = "loadAllAuthTree", method = { RequestMethod.POST })
  public String loadAllAuthTree(HttpServletRequest request, HttpServletResponse response) {
    String id = request.getParameter("id");
    List<Authority> checkedAuthList = roleService.getCheckedAuthIds(id);
    String authTreeJson = menusService.createAuthTree(checkedAuthList);
    log.info(authTreeJson);
    PrintWriter out;
    try {
      out = response.getWriter();
      out.print(authTreeJson);
      out.flush();
      out.close();
    } catch (IOException e) {
      log.error("处理json数据报错:" + e.getStackTrace());
    }
    return null;
  }
  /**
   * 验证用户名是否存在
   *
   * @param roleName
   * @return
   */
  // @RequestMapping(value = "validataRoleName", method = { RequestMethod.POST })
  public void validataRoleName(HttpServletResponse response, String roleName) {
    int i = roleService.valiedateRoleName(roleName);
    String ok = i + "";
    try {
      PrintWriter out = response.getWriter();
      out.write(ok);
      out.flush();
      out.close();
    } catch (IOException e) {
      log.error("处理数据报错:" + e.getStackTrace());
    }
  }
}
コード例 #20
0
ファイル: ResultSetLooping.java プロジェクト: xing-kenny/nutz
/**
 * 遍历 RersultSet
 *
 * @author zozoh([email protected])
 */
public abstract class ResultSetLooping {

  private static Log log = Logs.get();

  /** 当结果集大于指定数量时,输出警告日志,默认-1不启用 */
  public static int WARN_BIG_SIZE = -1;

  /** 当结果集大于指定大小时,报错,默认-1不启用 */
  public static int ERROR_BIG_SIZE = -1;

  /** 可以在SqlConext中设置key来实现单独配置 */
  public static String KEY_WARN_SIZE = "sql-result-size-warn";
  /** 可以在SqlConext中设置key来实现单独配置 */
  public static String KEY_ERROR_SIZE = "sql-result-size-error";

  protected List<Object> list;

  private int index;

  public ResultSetLooping() {
    list = new LinkedList<Object>();
    index = -1;
  }

  public void doLoop(ResultSet rs, SqlContext context) throws SQLException {
    Pager pager = context.getPager();
    if (null == rs) return;
    int warnSize =
        (context.attr(KEY_WARN_SIZE) == null
            ? WARN_BIG_SIZE
            : ((Number) (context.attr(KEY_WARN_SIZE))).intValue());
    int errorSize =
        (context.attr(KEY_ERROR_SIZE) == null
            ? ERROR_BIG_SIZE
            : ((Number) (context.attr(KEY_ERROR_SIZE))).intValue());
    boolean warnBigResult = log.isWarnEnabled() && warnSize > 0;
    boolean errorBigResult = errorSize > 0;
    /**
     * 如果没有设置 Pager 或者 rs 的类型是 ResultSet.TYPE_FORWARD_ONLY,那么<br>
     * 无法利用 游标的滚动 来计算结果集合大小。这比较高效,但是如果使用者希望得到页数量,<br>
     * 需要为 Pager 另行计算 总体的结果集大小。
     *
     * <p>一般的,为特殊数据建立的 Pager,生成的 ResultSet 类型应该是 TYPE_FORWARD_ONLY
     */
    if (null == pager
        || ResultSet.TYPE_FORWARD_ONLY == rs.getType()
        || pager.getPageNumber() <= 0) {
      // 根据 Pager 设定 Fetch Size
      // by wendal: 设置与否,影响不大的,而且旧版本的Oracle会出问题,故,注释掉了
      // if (null != pager && pager.getPageSize() > 0)
      //    rs.setFetchSize(pager.getPageSize());

      // 循环调用
      while (rs.next()) {
        createObject(++index, rs, context, -1);
        if (warnBigResult && index > warnSize) {
          warnBigResult = false;
          this.warnBig(rs, context, index, warnSize);
        }
        if (errorBigResult && index > errorSize) {
          errorBigResult = false;
          this.errorBig(rs, context, index, errorSize);
        }
      }
    }
    /**
     * 如果进行到了这个分支,则表示,整个查询的 Pager 是不区分数据库类型的。 <br>
     * 并且 ResultSet 的游标是可以来回滚动的。
     *
     * <p>所以我就会利用游标的滚动,为你计算整个结果集的大小。比较低效,在很小<br>
     * 数据量的时候 还是比较有用的
     */
    else if (rs.last()) {
      // 设置结果集合的 FetchSize
      if (pager.getPageSize() <= 0) rs.setFetchSize(Pager.DEFAULT_PAGE_SIZE);
      else if (pager.getPageSize() > Pager.MAX_FETCH_SIZE) rs.setFetchSize(Pager.MAX_FETCH_SIZE);
      else rs.setFetchSize(pager.getPageSize());

      // 开始循环
      int rowCount = rs.getRow();
      LoopScope ls = LoopScope.eval(pager, rowCount);
      if (rs.absolute(ls.start + 1))
        for (int i = ls.start; i < ls.max; i++) {
          createObject(++index, rs, context, rowCount);
          if (!rs.next()) break;
          if (warnBigResult && index > warnSize) {
            warnBigResult = false;
            this.warnBig(rs, context, index, warnSize);
          }
          if (errorBigResult && index > errorSize) {
            errorBigResult = false;
            this.errorBig(rs, context, index, errorSize);
          }
        }
    }
  }

  /** @return 当前获取的 List */
  public List<Object> getList() {
    return list;
  }

  /**
   * 获得最后一次回调被调用时的下标。 index 的值初始为 -1,每次调用回调前都会自增
   *
   * @return 当前循环的下标,下标由 0 开始
   */
  public int getIndex() {
    return index;
  }

  /**
   * 子类需要实现的函数
   *
   * @param index 当前下标
   * @param rs 结果集
   * @param context Sql 上下文
   * @param rowCount 总记录数,如果是原生分页语句,则会为 -1
   * @return 是否成功的创建了对象
   */
  protected abstract boolean createObject(
      int index, ResultSet rs, SqlContext context, int rowCount);

  protected void warnBig(ResultSet rs, SqlContext ctx, int index, int warnSize) {
    log.warnf("BIG Result, pager=%s", ctx.getPager());
  }

  protected void errorBig(ResultSet rs, SqlContext ctx, int index, int errorSize) {
    throw new DaoException("result size bigger than limit=" + errorSize);
  }
}
コード例 #21
0
public class DubboConfigureReader {

  private static final Log log = Logs.get();

  protected Map<String, Object> maps = new HashMap<>();

  public static Map<String, NutMap> read(String path) {
    Map<String, NutMap> maps = new LinkedHashMap<>();
    Document doc = Xmls.xml(DubboConfigureReader.class.getClassLoader().getResourceAsStream(path));
    doc.normalizeDocument();
    Element top = doc.getDocumentElement();
    NodeList list = top.getChildNodes();
    int count = list.getLength();

    for (int i = 0; i < count; i++) {
      Node node = list.item(i);
      if (node instanceof Element) {
        Element ele = (Element) node;
        String eleName = ele.getNodeName();
        if (!eleName.startsWith("dubbo:")) continue; // 跳过非dubbo节点
        String typeName = eleName.substring("dubbo:".length());
        NutMap attrs = toAttrMap(ele.getAttributes());
        log.debug("found " + typeName);
        String genBeanName = ele.getAttribute("id");
        if (Strings.isBlank(genBeanName)) {
          if ("protocol".equals(typeName)) genBeanName = "dubbo";
          else {
            genBeanName = ele.getAttribute("interface");
            if (Strings.isBlank(genBeanName)) {
              try {
                genBeanName =
                    Class.forName(
                            "com.alibaba.dubbo.config." + Strings.upperFirst(typeName) + "Config")
                        .getName();
              } catch (ClassNotFoundException e) {
                throw Lang.wrapThrow(e);
              }
            }
          }
          if (maps.containsKey(genBeanName)) {
            int _count = 2;
            while (true) {
              String key = genBeanName + "_" + _count;
              if (maps.containsKey(key)) {
                _count++;
                continue;
              }
              genBeanName += "_" + _count;
              break;
            }
          }
        }
        attrs.put("_typeName", typeName);
        maps.put(genBeanName, attrs);
      }
    }
    return maps;
  }

  public static NutMap toAttrMap(NamedNodeMap attrs) {
    NutMap map = new NutMap();
    int len = attrs.getLength();
    for (int j = 0; j < len; j++) {
      Attr attr = (Attr) attrs.item(j);
      map.put(attr.getName(), attr.getValue());
    }
    return map;
  }
}
コード例 #22
0
/**
 * 支持简单的懒加载机制的AnnotationEntityMaker
 *
 * @author wendal([email protected])
 */
public class LazyAnnotationEntityMaker extends AnnotationEntityMaker {

  private static final Log log = Logs.get();

  private Dao dao;

  public LazyAnnotationEntityMaker(
      DataSource datasource, JdbcExpert expert, EntityHolder holder, Dao dao) {
    super(datasource, expert, holder);
    this.dao = dao;
  }

  protected <T> NutEntity<T> _createNutEntity(Class<T> type) {
    return new LazyNutEntity<T>(type);
  }

  @Override
  public <T> Entity<T> make(Class<T> type) {
    LazyNutEntity<T> en = (LazyNutEntity<T>) super.make(type);
    en.init();
    return en;
  }

  class LazyNutEntity<T> extends NutEntity<T> {

    public LazyNutEntity(Class<T> type) {
      super(type);
    }

    @SuppressWarnings({"rawtypes", "unchecked"})
    public void init() {
      List<LinkField> lfs = new ArrayList<LinkField>();
      lfs.addAll(ones.getAll());
      lfs.addAll(manys.getAll());
      lfs.addAll(manymanys.getAll());
      if (lfs.isEmpty()) return;
      if (log.isDebugEnabled()) log.debug("Found links , enable lazy!! -->" + type);

      Mirror<T> mirror = Mirror.me(type);
      List<InterceptorPair> interceptorPairs = new ArrayList<InterceptorPair>();
      // 准备拦截器
      for (LinkField lf : lfs) {
        String fieldName = lf.getName();
        try {
          Method setter = mirror.getSetter(mirror.getField(fieldName));
          LazyMethodInterceptor lmi = new LazyMethodInterceptor(setter, fieldName);
          interceptorPairs.add(
              new InterceptorPair(
                  lmi,
                  MethodMatcherFactory.matcher(
                      "^(get|set)" + Strings.upperFirst(fieldName) + "$")));
        } catch (Throwable e) {
          if (log.isWarnEnabled()) log.warn("Not setter found for LazyLoading ?!", e);
        }
      }
      // 生成Aop化的类
      ClassAgent agent = new AsmClassAgent();
      for (InterceptorPair interceptorPair : interceptorPairs)
        agent.addInterceptor(
            interceptorPair.getMethodMatcher(), interceptorPair.getMethodInterceptor());
      Class lazyClass = agent.define(DefaultClassDefiner.defaultOne(), type);

      // 检查对象的创建方法
      BornContext<T> bc = Borns.evalByArgTypes(type, ResultSet.class);
      if (null == bc) this.bornByDefault = Mirror.me(lazyClass).getBorningByArgTypes();
      else this.bornByRS = bc.getBorning();
    }
  }

  class LazyMethodInterceptor implements MethodInterceptor {

    private WeakHashMap<Object, LazyStatus> status =
        new WeakHashMap<Object, LazyAnnotationEntityMaker.LazyStatus>();

    private Method setter;
    private String fieldName;

    public LazyMethodInterceptor(Method setter, String fieldName) {
      this.setter = setter;
      this.fieldName = fieldName;
    }

    public void filter(InterceptorChain chain) throws Throwable {
      LazyStatus stat = status.get(chain.getCallingObj());
      if (stat == null) {
        if (!chain.getCallingMethod().equals(setter)) {
          dao.fetchLinks(chain.getCallingObj(), fieldName); // 这里会触发setter被调用
        }
        status.put(chain.getCallingObj(), LazyStatus.NO_NEED); // 如果setter被调用,那么也就不再需要懒加载了
      }
      chain.doChain();
    }
  }

  enum LazyStatus {
    CAN_FETCH,
    FETCHED,
    NO_NEED
  }
}
コード例 #23
0
/**
 * 定期将未读的消息发送成 Email
 *
 * @author zozoh([email protected])
 */
@IocBean(name = "t_msg_mail")
public class MesssageMailMaker implements TimerHandler {

  private static final Log log = Logs.get();

  /** 注入: 服务类工厂 */
  @Inject("refer:serviceFactory")
  private ZTaskFactory factory;

  @Override
  public String doHandle(String name, Timering ing) {
    final Map<String, List<Message>> map = new HashMap<String, List<Message>>();
    // 分组
    factory
        .messages()
        .each(
            null,
            "!R!N:",
            null,
            0,
            new Each<Message>() {
              public void invoke(int index, Message msg, int length) {
                List<Message> list = map.get(msg.getOwner());
                if (null == list) {
                  list = new LinkedList<Message>();
                  map.put(msg.getOwner(), list);
                }
                list.add(msg);
              }
            });

    if (log.isDebugEnabled())
      log.debugf("MailMaker: found %d users %s", map.size(), Strings.dup('*', 40));

    // 循环为每个用户发送通知邮件
    for (String unm : map.keySet()) {

      User u = factory.users().get(unm);
      if (null == u || null == u.getEmail()) continue;

      List<Message> list = map.get(unm);

      if (null == list || list.isEmpty()) {
        continue;
      }

      if (log.isDebugEnabled()) log.debugf(" - MailMaker: will send to '%s'", unm);

      Date now = Times.now();

      // 准备消息
      StringBuilder sb = new StringBuilder();
      sb.append("Message in zTask @ " + Times.sDT(now) + " : \n\n");
      for (Message msg : list) {
        sb.append("   [").append(Times.sDT(msg.getCreateTime())).append("] - ");
        sb.append(msg.getText());
        sb.append("\n");
      }
      sb.append("\n\n");

      Message firstMsg = list.get(0);
      String subject =
          String.format(
              "[zTask:%d] %s ",
              list.size(), firstMsg.getText().replaceAll("[\\[]?[0-9a-f]{24}[\\]]?", ""));

      if (log.isDebugEnabled()) log.debugf(" - MailMaker: mail is: '%s':\n%s", subject, sb);

      // 设置收件人
      MailObj mo = ZTasks.textMail(subject, sb.toString());
      mo.setTos(Lang.array(u.getName()));

      if (log.isDebugEnabled())
        log.debugf(" - MailMaker: mail to @%s(%s)", u.getName(), u.getEmail());

      // 加入队列
      factory.mails().joinMail(mo);

      if (log.isDebugEnabled())
        log.debugf(" - MailMaker: after join, queue(%d)", factory.mails().count());

      // 设置通知状态
      for (Message msg : list) factory.messages().setNotified(msg, now);

      if (log.isDebugEnabled()) {
        log.debugf(" - MailMaker: set noti for %d messages", list.size());
        log.debugf(" - MailMaker: %s -- NEXT LOOP --", Strings.dup('-', 28));
      }
    }

    // 返回成功
    return "OK:" + map.size() + " users";
  }
}
コード例 #24
0
ファイル: UploadingContext.java プロジェクト: xing-kenny/nutz
/**
 * 执行上传时一些必要的配置信息
 *
 * @author zozoh([email protected])
 */
public class UploadingContext {

  private static final Log log = Logs.get();

  public static UploadingContext create(String poolPath) {
    return create(new NutFilePool(poolPath));
  }

  public static UploadingContext create(FilePool pool) {
    return new UploadingContext(pool);
  }

  public UploadingContext(String poolPath) {
    this(new NutFilePool(poolPath, 2000));
  }

  public UploadingContext(FilePool pool) {
    charset = Encoding.UTF8;
    bufferSize = 8192;
    setFilePool(pool);
  }

  /** 默认为 UTF-8,上传字节流的编码 */
  private String charset;

  /** 临时文件池 */
  private FilePool filePool;

  /** 缓冲,默认 8192 */
  private int bufferSize;

  /** 是否忽略空文件,默认为 false */
  private boolean ignoreNull;

  /**
   * 如果大于0,对于每个上传的文件,都判断,如果超过了这个大小,则拒绝继续上传
   *
   * <p>单位为字节
   */
  private int maxFileSize;

  /** 一个正则表达式,描述了可以允许的文件名 */
  private String nameFilter;

  /** 一个正则表达式,描述了可以允许的文件内容类型 */
  private String contentTypeFilter;

  public String getCharset() {
    return charset;
  }

  public UploadingContext setCharset(String charset) {
    this.charset = charset;
    return this;
  }

  public FilePool getFilePool() {
    return filePool;
  }

  public UploadingContext setFilePool(FilePool pool) {
    if (!(pool instanceof SynchronizedFilePool)) pool = new SynchronizedFilePool(pool);
    this.filePool = pool;
    return this;
  }

  public int getBufferSize() {
    return bufferSize;
  }

  public UploadingContext setBufferSize(int bufferSize) {
    this.bufferSize = bufferSize;
    if (bufferSize < 128 && log.isWarnEnabled()) {
      log.warn("Uploading buffer is less than 128!! Auto-fix to 128!! 8192 will be much better!!");
      this.bufferSize = 128;
    }
    return this;
  }

  public boolean isIgnoreNull() {
    return ignoreNull;
  }

  public UploadingContext setIgnoreNull(boolean ignoreNull) {
    this.ignoreNull = ignoreNull;
    return this;
  }

  public int getMaxFileSize() {
    return maxFileSize;
  }

  public UploadingContext setMaxFileSize(int maxFileSize) {
    this.maxFileSize = maxFileSize;
    return this;
  }

  public String getNameFilter() {
    return nameFilter;
  }

  public UploadingContext setNameFilter(String nameFilter) {
    this.nameFilter = nameFilter;
    return this;
  }

  public boolean isNameAccepted(String name) {
    if (null == nameFilter
        || Strings.isBlank(name)
        || "\"\"".equals(name)) // 用户不选择文件时,文件名会是"" 两个双引号
    return true;
    return Pattern.matches(nameFilter, name.toLowerCase());
  }

  public String getContentTypeFilter() {
    return contentTypeFilter;
  }

  public UploadingContext setContentTypeFilter(String contentTypeFilter) {
    this.contentTypeFilter = contentTypeFilter;
    return this;
  }

  public boolean isContentTypeAccepted(String contentType) {
    if (null == contentTypeFilter || Strings.isBlank(contentType)) return true;
    return Pattern.matches(contentTypeFilter, contentType.toLowerCase());
  }
}
コード例 #25
0
ファイル: UploadAdaptor.java プロジェクト: JRed1989/nutz
/**
 * 本适配器专门处理 HTTP 文件上传(1.b.44及之后的版本,兼容Html5的流式上传)。 它支持多文件,多参数上传。具体的做法是将 HTTP 上传的所有内容
 * 包括文件以及名值对都预先缓存下来。其中,文件缓存在磁盘上,名值对缓存在内存中。
 *
 * <p>因此,本适配器构造的时候,需要四个参数:
 *
 * <ol>
 *   <li>临时文件存放的目录
 *   <li>数据缓冲区大小,建议设置为8192
 *   <li>HTTP 请求的编码方式。
 *   <li>临时文件的最大数量
 * </ol>
 *
 * 本适配器提供了四个构造函数,最简单的一个只有一个参数,需要你提供一个临时文件目录,缓冲区大小默认为8192, 临时文件数目默认的为 "2000",HTTP 请求的编码方式为 "UTF-8",
 *
 * <p>为了能让入口函数了解 HTTP 请求的更多信息,本适配器入口函数声明更多的参数类型:
 *
 * <ul>
 *   <li>java.io.File : 指向已上传至临时目录的文件对象
 *   <li>org.nutz.mvc.upload.FieldMeta : 描述了一个上传参数的更多属性
 *   <li>org.nutz.mvc.upload.TempFile : 组合了 File 和 FieldMeta
 * </ul>
 *
 * 当然,这三种参数,都是需要你在入口函数的参数列表里声明 '@Param' 注解,用来告诉本适配器,你的参数 具体取自请求中的哪一个参数。
 *
 * <p><b>Html5流式上传(实验性)的注意事项: 参数名默认是filedata,除非req.getHeader("Content-Disposition")中有描述另外的name</b>
 *
 * @author zozoh([email protected])
 * @author wendal([email protected])
 * @see org.nutz.mvc.annotation.Param
 */
public class UploadAdaptor extends PairAdaptor {
  private static final Log log = Logs.get();

  private UploadingContext context;

  public UploadAdaptor() throws IOException {
    context = new UploadingContext(File.createTempFile("nutz", null).getParent());
  }

  public UploadAdaptor(UploadingContext context) {
    this.context = context;
  }

  public UploadAdaptor(String path) {
    context = new UploadingContext(path);
  }

  public UploadAdaptor(String path, int buffer) {
    this(path);
    context.setBufferSize(buffer);
  }

  public UploadAdaptor(String path, int buffer, String charset) {
    this(path);
    context.setBufferSize(buffer);
    context.setCharset(charset);
  }

  public UploadAdaptor(String path, int buffer, String charset, int poolSize) {
    context = new UploadingContext(new NutFilePool(path, poolSize));
    context.setBufferSize(buffer);
    context.setCharset(charset);
  }

  public UploadAdaptor(String path, int buffer, String charset, int poolSize, int maxFileSize) {
    context = new UploadingContext(new NutFilePool(path, poolSize));
    context.setBufferSize(buffer);
    context.setCharset(charset);
    context.setMaxFileSize(maxFileSize);
  }

  public UploadingContext getContext() {
    return context;
  }

  @Override
  public Object[] adapt(
      ServletContext sc, HttpServletRequest req, HttpServletResponse resp, String[] pathArgs) {

    // 临时
    if (!Mvcs.getActionContext().getMethod().toGenericString().equals(method.toGenericString())) {
      throw new IllegalArgumentException(
          String.format(
              "Method miss match: expect %s but %s. using Ioc? set singleton=false, pls",
              method, Mvcs.getActionContext().getMethod()));
    }
    return super.adapt(sc, req, resp, pathArgs);
  }

  protected ParamInjector evalInjectorBy(Type type, Param param) {
    // TODO 这里的实现感觉很丑, 感觉可以直接用type进行验证与传递
    // TODO 这里将Type的影响局限在了 github issue #30 中提到的局部范围
    Class<?> clazz = Lang.getTypeClass(type);
    if (clazz == null) {
      if (log.isWarnEnabled())
        log.warnf("!!Fail to get Type Class : type=%s , param=%s", type, param);
      return null;
    }

    // Map
    if (Map.class.isAssignableFrom(clazz)) return new MapSelfInjector();

    if (null == param) return super.evalInjectorBy(type, null);

    String paramName = param.value();

    // File
    if (File.class.isAssignableFrom(clazz)) return new FileInjector(paramName);
    // FileMeta
    if (FieldMeta.class.isAssignableFrom(clazz)) return new FileMetaInjector(paramName);
    // TempFile
    if (TempFile.class.isAssignableFrom(clazz)) return new TempFileInjector(paramName);
    // InputStream
    if (InputStream.class.isAssignableFrom(clazz)) return new InputStreamInjector(paramName);
    // Reader
    if (Reader.class.isAssignableFrom(clazz)) return new ReaderInjector(paramName);
    // List
    if (List.class.isAssignableFrom(clazz)) return new MapListInjector(paramName);
    if (TempFile[].class.isAssignableFrom(clazz)) {
      return new TempFileArrayInjector(paramName);
    }
    // Other
    return super.evalInjectorBy(type, param);
  }

  public Map<String, Object> getReferObject(
      ServletContext sc,
      HttpServletRequest request,
      HttpServletResponse response,
      String[] pathArgs) {
    try {
      if (!"POST".equals(request.getMethod()) && !"PUT".equals(request.getMethod())) {
        String str = "Not POST or PUT, Wrong HTTP method! --> " + request.getMethod();
        throw Lang.makeThrow(IllegalArgumentException.class, str);
      }
      // 看看是不是传统的上传
      String contentType = request.getContentType();
      if (contentType == null) {
        throw Lang.makeThrow(IllegalArgumentException.class, "Content-Type is NULL!!");
      }
      if (contentType.contains("multipart/form-data")) { // 普通表单上传
        if (log.isDebugEnabled())
          log.debug("Select Html4 Form upload parser --> " + request.getRequestURI());
        Uploading ing = new FastUploading();
        return ing.parse(request, context);
      }
      if (contentType.contains("application/octet-stream")) { // Html5
        // 流式上传
        if (log.isDebugEnabled())
          log.debug("Select Html5 Stream upload parser --> " + request.getRequestURI());
        Uploading ing = new Html5Uploading();
        return ing.parse(request, context);
      }
      // 100%是没写enctype='multipart/form-data'
      if (contentType.contains("application/x-www-form-urlencoded")) {
        log.warn("Using form upload ? You forgot this --> enctype='multipart/form-data' ?");
      }
      throw Lang.makeThrow(IllegalArgumentException.class, "Unknow Content-Type : " + contentType);
    } catch (UploadException e) {
      throw Lang.wrapThrow(e);
    } finally {
      Uploads.removeInfo(request);
    }
  }
}
コード例 #26
0
public class NutQuartzCronJobFactory {

  private static final Log log = Logs.get();

  protected PropertiesProxy conf;

  protected Scheduler scheduler;

  public void init() throws Exception {
    String prefix = "cron.";
    for (String key : conf.getKeys()) {
      if (key.length() < prefix.length() + 1 || !key.startsWith(prefix)) continue;
      String name = key.substring(prefix.length());
      if ("pkgs".equals(name)) {
        log.debug("found cron job packages = " + conf.get(key));
        for (String pkg : Strings.splitIgnoreBlank(conf.get(key), ",")) {
          addPackage(pkg);
        }
        continue;
      }
      String cron = conf.get(key);
      log.debugf("job define name=%s cron=%s", name, cron);
      Class<?> klass = null;
      if (name.contains(".")) {
        klass = Lang.loadClass(name);
      } else {
        klass = Lang.loadClass(getClass().getPackage().getName() + ".job." + name);
      }
      cron(cron, klass);
    }
  }

  public void addPackage(String pkg) {
    for (Class<?> klass : Scans.me().scanPackage(pkg)) {
      Scheduled scheduled = klass.getAnnotation(Scheduled.class);
      if (scheduled != null) {
        try {
          add(klass, scheduled);
        } catch (SchedulerException e) {
          throw new RuntimeException(e);
        }
      }
    }
  }

  @SuppressWarnings("unchecked")
  public void add(Class<?> klass, Scheduled scheduled) throws SchedulerException {
    String name = klass.getName();
    if (!Strings.isBlank(scheduled.cron())) {
      try {
        log.debugf("job define name=%s cron=%s", name, scheduled.cron());
        cron(scheduled.cron(), klass);
        return;
      } catch (SchedulerException e) {
        throw new RuntimeException(e);
      }
    }
    if (scheduled.fixedRate() > 0) {
      log.debugf(
          "job define name=%s fixedRate=%s count=%s initialDelay=%s",
          name, scheduled.fixedRate(), scheduled.count(), scheduled.initialDelay());
      SimpleScheduleBuilder schedule = SimpleScheduleBuilder.simpleSchedule();
      if (scheduled.fixedRate() > 0) schedule.withIntervalInSeconds(scheduled.fixedRate());
      if (scheduled.count() > 0) {
        schedule.withRepeatCount(scheduled.count());
      } else {
        schedule.repeatForever();
      }
      TriggerBuilder<SimpleTrigger> trigger =
          TriggerBuilder.newTrigger().withIdentity(name).withSchedule(schedule);
      if (scheduled.initialDelay() > 0)
        trigger.startAt(new Date(System.currentTimeMillis() + scheduled.initialDelay() * 1000));

      JobDetail job = JobBuilder.newJob((Class<? extends Job>) klass).withIdentity(name).build();
      scheduler.scheduleJob(job, trigger.build());
    }
  }

  @SuppressWarnings("unchecked")
  public void cron(String cron, Class<?> klass) throws SchedulerException {
    String name = klass.getName();
    JobDetail job = JobBuilder.newJob((Class<? extends Job>) klass).withIdentity(name).build();
    CronTrigger trigger =
        TriggerBuilder.newTrigger()
            .withIdentity(name)
            .withSchedule(CronScheduleBuilder.cronSchedule(cron))
            .build();
    scheduler.scheduleJob(job, trigger);
  }
}
コード例 #27
0
ファイル: InterceptorChain.java プロジェクト: GTDaven/nutz
/**
 * 拦截器链,持有被调用方法的信息
 *
 * @author wendal([email protected])
 */
public class InterceptorChain {

  protected Method callingMethod;

  protected int methodIndex;

  protected Object args[];

  protected AopCallback callingObj;

  protected Object returnValue;

  protected List<MethodInterceptor> miList;

  private static Log LOG = Logs.get();

  private boolean invoked = false;

  private int currentMI = 0;

  public InterceptorChain(
      int methodIndex, Object obj, Method method, List<MethodInterceptor> miList, Object[] args) {
    this.methodIndex = methodIndex;
    this.callingObj = (AopCallback) obj;
    this.callingMethod = method;
    this.args = args;
    this.miList = miList;
  }

  /**
   * 继续执行下一个拦截器,如果已经没有剩下的拦截器,则执行原方法
   *
   * @return 拦截器链本身
   * @throws Throwable 下层拦截器或原方法抛出的一切异常
   */
  public InterceptorChain doChain() throws Throwable {
    if (currentMI == miList.size()) invoke();
    else {
      currentMI++;
      miList.get(currentMI - 1).filter(this);
    }
    return this;
  }

  /**
   * 执行原方法,一般情况下不应该直接被调用
   *
   * @throws Throwable 原方法抛出的一切异常
   */
  public void invoke() throws Throwable {
    if (invoked)
      LOG.warnf("!! Calling Method more than once! Method --> %s", callingMethod.toString());
    else invoked = true;
    this.returnValue = callingObj._aop_invoke(methodIndex, args);
  }

  /**
   * 获取返回值
   *
   * @return 返回值
   */
  public Object getReturn() {
    return returnValue;
  }

  /** 正在被调用的Method */
  public Method getCallingMethod() {
    return callingMethod;
  }

  /** 方法调用的参数数组,如果你要改变参数,那么必须保证参数类型与方法参数兼容. */
  public Object[] getArgs() {
    return args;
  }

  public void setReturnValue(Object returnValue) {
    this.returnValue = returnValue;
  }

  public AopCallback getCallingObj() {
    return callingObj;
  }

  public boolean isInvoked() {
    return invoked;
  }

  /** 获取当前的方法拦截器列表,注意,这个列表是不可修改的.如果需要修改,那么请通过{@link #setMethodInterceptors(List)} */
  public List<MethodInterceptor> getMethodInterceptors() {
    return Collections.unmodifiableList(miList);
  }

  /** 设置当前调用的方法拦截器列表,注意,这个set只对当前方法调用有效. */
  public void setMethodInterceptors(List<MethodInterceptor> miList) {
    this.miList = miList;
  }
}
コード例 #28
0
ファイル: TcpServer.java プロジェクト: uohzoaix/stormManager
/**
 * 提供一个简易的 TCP 的 socket 监听服务器
 *
 * @author zozoh([email protected])
 */
public class TcpServer implements Runnable {

  private static final Log log = Logs.get();

  private boolean stop;

  private int port;

  private ServerSocket listener;

  private SocketHandler handler;

  public TcpServer(int port, SocketHandler handler) {
    this.port = port;
    this.handler = handler;
  }

  protected void listen(Socket socket) {
    SocketHandler handler = getHandler();
    // 处理请求
    try {
      handler.handle(socket);
    }
    // 仅仅是关闭连接
    catch (SocketClosed e) {
    }
    // 停止服务
    catch (ServerStopped e) {
      stop = true;
    }
    // 处理异常
    catch (Throwable e) {
      handler.whenError(socket, e);
    }
    // 确保关闭
    finally {
      if (!socket.isClosed())
        try {
          socket.close();
        } catch (IOException e) {
          throw Lang.wrapThrow(e);
        }
    }
  }

  public void run() {
    // ----------------------------------------- 建立
    log.infof("start TcpServer [%s] @ %d", Thread.currentThread().getName(), port);
    try {
      listener = new ServerSocket(port);
    } catch (IOException e1) {
      throw Lang.wrapThrow(e1);
    }
    // ----------------------------------------- 循环
    log.infof("TcpServer listen @ %d", port);
    while (!stop) {
      log.info("before accept ...");
      Socket socket = null;
      try {
        socket = listener.accept();
      } catch (IOException e) {
        log.fatalf("Fail to accept %s @ %d , System.exit!", Thread.currentThread().getName(), port);
        System.exit(0);
      }

      log.info("do listen ...");
      listen(socket);
      log.infof(
          "done for listen [%s:%d], stop=%b",
          socket.getInetAddress().getHostName(), socket.getPort(), stop);
    }
    // ----------------------------------------- 关闭
    try {
      listener.close();
      log.infof("TcpServer shutdown @ %d", port);
    } catch (IOException e) {
      throw Lang.wrapThrow(e);
    }
  }

  public SocketHandler getHandler() {
    return handler;
  }

  public void setHandler(SocketHandler handler) {
    this.handler = handler;
  }

  public void stop() {
    stop = true;
  }
}
コード例 #29
0
/**
 * Nutz内核初始化完成后的操作
 *
 * @author wendal
 */
public class MainSetup implements Setup {

  private static final Log log = Logs.get();

  @SuppressWarnings("serial")
  public void init(NutConfig nc) {
    NutShiro.DefaultLoginURL = "/admin/logout";
    // 检查环境
    if (!Charset.defaultCharset().name().equalsIgnoreCase(Encoding.UTF8)) {
      log.warn("This project must run in UTF-8, pls add -Dfile.encoding=UTF-8 to JAVA_OPTS");
    }

    // 获取Ioc容器及Dao对象
    Ioc ioc = nc.getIoc();
    // 加载freemarker自定义标签 自定义宏路径
    ioc.get(Configuration.class)
        .setAutoImports(
            new HashMap<String, String>(2) {
              {
                put("p", "/ftl/pony/index.ftl");
                put("s", "/ftl/spring.ftl");
              }
            });
    ioc.get(FreeMarkerConfigurer.class, "mapTags");
    Dao dao = ioc.get(Dao.class);

    // 为全部标注了@Table的bean建表
    Daos.createTablesInPackage(dao, getClass().getPackage().getName() + ".bean", false);

    // 获取配置对象
    PropertiesProxy conf = ioc.get(PropertiesProxy.class, "conf");

    // 初始化SysLog,触发全局系统日志初始化
    ioc.get(SysLogService.class);

    // 初始化默认根用户
    User admin = dao.fetch(User.class, "admin");
    if (admin == null) {
      UserService us = ioc.get(UserService.class);
      admin = us.add("admin", "123456");
    }
    // 初始化游客用户
    User guest = dao.fetch(User.class, "guest");
    if (guest == null) {
      UserService us = ioc.get(UserService.class);
      guest = us.add("guest", "123456");
      UserProfile profile = dao.fetch(UserProfile.class, guest.getId());
      profile.setNickname("游客");
      dao.update(profile, "nickname");
    }

    // 获取NutQuartzCronJobFactory从而触发计划任务的初始化与启动
    ioc.get(NutQuartzCronJobFactory.class);

    // 权限系统初始化
    AuthorityService as = ioc.get(AuthorityService.class);
    as.initFormPackage("net.wendal.nutzbook");
    as.checkBasicRoles(admin);

    // 检查一下Ehcache CacheManager 是否正常.
    CacheManager cacheManager = ioc.get(CacheManager.class);
    log.debug("Ehcache CacheManager = " + cacheManager);
    // CachedNutDaoExecutor.DEBUG = true;

    // 启用FastClass执行入口方法
    Mvcs.disableFastClassInvoker = false;

    // 设置Markdown缓存
    if (cacheManager.getCache("markdown") == null) cacheManager.addCache("markdown");
    Markdowns.cache = cacheManager.getCache("markdown");
    if (conf.getBoolean("cdn.enable", false) && !Strings.isBlank(conf.get("cdn.urlbase"))) {
      MarkdownFunction.cdnbase = conf.get("cdn.urlbase");
    }
  }

  public void destroy(NutConfig conf) {
    Markdowns.cache = null;
    // 非mysql数据库,或多webapp共享mysql驱动的话,以下语句删掉
    try {
      Mirror.me(Class.forName("com.mysql.jdbc.AbandonedConnectionCleanupThread"))
          .invoke(null, "shutdown");
    } catch (Throwable e) {
    }
    // 解决quartz有时候无法停止的问题
    try {
      conf.getIoc().get(Scheduler.class).shutdown(true);
    } catch (Exception e) {
    }
  }
}
コード例 #30
0
ファイル: AbstractJdbcExpert.java プロジェクト: ansjsun/nutz
/**
 * 对于所有数据库的抽象实现
 *
 * @author zozoh([email protected])
 */
public abstract class AbstractJdbcExpert implements JdbcExpert {

  private static final Log log = Logs.get();

  private static String DEFAULT_COMMENT_TABLE = "comment on table $table is '$tableComment'";

  private static String DEFAULT_COMMENT_COLUMN =
      "comment on column $table.$column is '$columnComment'";

  protected Set<String> keywords;

  /** 提供给子类使用的配置文件对象 */
  protected JdbcExpertConfigFile conf;

  // ====================================================================
  // 构造函数:子类需要将重载
  public AbstractJdbcExpert(JdbcExpertConfigFile conf) {
    this.conf = conf;
  }

  // ====================================================================
  // 下面为子类默认实现几个接口函数

  public void setupEntityField(Connection conn, Entity<?> en) {
    Statement stat = null;
    ResultSet rs = null;
    ResultSetMetaData rsmd = null;
    try {
      // 获取数据库元信息
      stat = conn.createStatement();
      rs = stat.executeQuery(createResultSetMetaSql(en));
      rsmd = rs.getMetaData();
      // 循环字段检查
      for (MappingField mf : en.getMappingFields()) {
        try {
          int ci = Daos.getColumnIndex(rsmd, mf.getColumnName());
          // 是否只读,如果人家已经是指明是只读了,那么就不要自作聪明得再从数据库里验证了
          // if (!mf.isReadonly() && rsmd.isReadOnly(ci))
          // mf.setAsReadonly();
          // 是否非空
          if (ResultSetMetaData.columnNoNulls == rsmd.isNullable(ci)) mf.setAsNotNull();
          // 枚举类型在数据库中的值
          if (mf.getTypeMirror().isEnum()) {
            if (Daos.isIntLikeColumn(rsmd, ci)) {
              mf.setColumnType(ColType.INT);
            } else {
              mf.setColumnType(ColType.VARCHAR);
            }
          }
        } catch (Exception e) {
          // TODO 需要log一下不?
        }
      }
    } catch (Exception e) {
      if (log.isDebugEnabled()) log.debugf("Table '%s' doesn't exist!", en.getViewName());
    }
    // Close ResultSet and Statement
    finally {
      Daos.safeClose(stat, rs);
    }
  }

  public ValueAdaptor getAdaptor(MappingField ef) {
    Mirror<?> mirror = ef.getTypeMirror();
    // 为数字型枚举的特殊判断
    if (mirror.isEnum() && ColType.INT == ef.getColumnType()) return Jdbcs.Adaptor.asEnumInt;
    // 用普通逻辑返回适配器
    return Jdbcs.getAdaptor(mirror);
  }

  public Pojo createPojo(SqlType type) {
    return new NutPojo().setSqlType(type);
  }

  public boolean dropEntity(Dao dao, Entity<?> en) {
    String tableName = en.getTableName();
    String viewName = en.getViewName();

    try {
      dropRelation(dao, en);
      if (!tableName.equals(viewName) && dao.exists(viewName)) {
        dao.execute(Sqls.create("DROP VIEW " + viewName));
      }
      dao.execute(Sqls.create("DROP TABLE " + tableName));
    } catch (Exception e) {
      return false;
    }
    return true;
  }

  public Map<String, Object> getConf() {
    return this.conf.getConfig();
  }

  // ====================================================================
  // 下面是提供给子类使用的一些帮助函数

  protected String createResultSetMetaSql(Entity<?> en) {
    return "SELECT * FROM " + en.getViewName() + " where 1!=1";
  }

  public void createRelation(Dao dao, Entity<?> en) {
    final List<Sql> sqls = new ArrayList<Sql>(5);
    for (LinkField lf : en.visitManyMany(null, null, null)) {
      ManyManyLinkField mm = (ManyManyLinkField) lf;
      if (dao.exists(mm.getRelationName())) continue;
      String sql = "CREATE TABLE " + mm.getRelationName() + "(";
      sql += mm.getFromColumnName() + " " + evalFieldType(mm.getHostField()) + ",";
      sql += mm.getToColumnName() + " " + evalFieldType(mm.getLinkedField());
      sql += ")";
      sqls.add(Sqls.create(sql));
    }
    dao.execute(sqls.toArray(new Sql[sqls.size()]));
  }

  protected void dropRelation(Dao dao, Entity<?> en) {
    final List<Sql> sqls = new ArrayList<Sql>(5);
    for (LinkField lf : en.visitManyMany(null, null, null)) {
      ManyManyLinkField mm = (ManyManyLinkField) lf;
      if (!dao.exists(mm.getRelationName())) continue;
      sqls.add(Sqls.create("DROP TABLE " + mm.getRelationName()));
    }
    dao.execute(sqls.toArray(new Sql[sqls.size()]));
  }

  public String evalFieldType(MappingField mf) {
    if (mf.getCustomDbType() != null) return mf.getCustomDbType();
    switch (mf.getColumnType()) {
      case CHAR:
        return "CHAR(" + mf.getWidth() + ")";

      case BOOLEAN:
        return "BOOLEAN";

      case VARCHAR:
        return "VARCHAR(" + mf.getWidth() + ")";

      case TEXT:
        return "TEXT";

      case BINARY:
        return "BLOB";

      case TIMESTAMP:
        return "TIMESTAMP";

      case DATETIME:
        return "DATETIME";

      case DATE:
        return "DATE";
      case TIME:
        return "TIME";

      case INT:
        // 用户自定义了宽度
        if (mf.getWidth() > 0) return "INT(" + mf.getWidth() + ")";
        // 用数据库的默认宽度
        return "INT";

      case FLOAT:
        // 用户自定义了精度
        if (mf.getWidth() > 0 && mf.getPrecision() > 0) {
          return "NUMERIC(" + mf.getWidth() + "," + mf.getPrecision() + ")";
        }
        // 用默认精度
        if (mf.getTypeMirror().isDouble()) return "NUMERIC(15,10)";
        return "FLOAT";

      case PSQL_ARRAY:
        return "ARRAY";

      case PSQL_JSON:
      case MYSQL_JSON:
        return "JSON";
        // TODO 这里不用加 default 么
    }
    throw Lang.makeThrow(
        "Unsupport colType '%s' of field '%s' in '%s' ",
        mf.getColumnType(), mf.getName(), mf.getEntity().getType().getName());
  }

  protected static List<DaoStatement> wrap(String... sqls) {
    List<DaoStatement> sts = new ArrayList<DaoStatement>(sqls.length);
    for (String sql : sqls) if (!Strings.isBlank(sql)) sts.add(Sqls.create(sql));
    return sts;
  }

  protected static List<DaoStatement> wrap(List<String> sqls) {
    List<DaoStatement> sts = new ArrayList<DaoStatement>(sqls.size());
    for (String sql : sqls) if (!Strings.isBlank(sql)) sts.add(Sqls.create(sql));
    return sts;
  }

  protected static String gSQL(String ptn, String table, String field) {
    CharSegment cs = new CharSegment(ptn);
    cs.set("T", table).set("F", field);
    return cs.toString();
  }

  protected String getDefaultValue(MappingField mf) {
    return mf.getDefaultValue(null).replaceAll("@", "@@");
  }

  protected List<Sql> createIndexs(Entity<?> en) {
    List<Sql> sqls = new ArrayList<Sql>();
    StringBuilder sb = new StringBuilder();
    List<EntityIndex> indexs = en.getIndexes();
    for (EntityIndex index : indexs) {
      sb.setLength(0);
      if (index.isUnique()) sb.append("Create UNIQUE Index ");
      else sb.append("Create Index ");
      if (index.getName().contains("$"))
        sb.append(TableName.render(new CharSegment(index.getName())));
      else sb.append(index.getName());
      sb.append(" ON ").append(en.getTableName()).append("(");
      for (EntityField field : index.getFields()) {
        if (field instanceof MappingField) {
          MappingField mf = (MappingField) field;
          sb.append(mf.getColumnNameInSql()).append(',');
        } else {
          throw Lang.makeThrow(
              DaoException.class,
              "%s %s is NOT a mapping field, can't use as index field!!",
              en.getClass(),
              field.getName());
        }
      }
      sb.setCharAt(sb.length() - 1, ')');
      sqls.add(Sqls.create(sb.toString()));
    }
    return sqls;
  }

  public void addComment(Dao dao, Entity<?> en) {
    addComment(dao, en, null, null);
  }

  public void addComment(Dao dao, Entity<?> en, String commentTable, String commentColumn) {
    if (!en.hasTableComment() && !en.hasColumnComment()) {
      return;
    }
    List<Sql> sqls = new ArrayList<Sql>();
    // 表注释
    if (en.hasTableComment()) {
      Sql tableCommentSQL =
          Sqls.create(Strings.isBlank(commentTable) ? DEFAULT_COMMENT_TABLE : commentTable);
      tableCommentSQL
          .vars()
          .set("table", en.getTableName())
          .set("tableComment", en.getTableComment());
      sqls.add(tableCommentSQL);
    }
    // 字段注释
    if (en.hasColumnComment()) {
      for (MappingField mf : en.getMappingFields()) {
        if (mf.hasColumnComment()) {
          Sql columnCommentSQL =
              Sqls.create(Strings.isBlank(commentColumn) ? DEFAULT_COMMENT_COLUMN : commentColumn);
          columnCommentSQL
              .vars()
              .set("table", en.getTableName())
              .set("column", mf.getColumnName())
              .set("columnComment", mf.getColumnComment());
          sqls.add(columnCommentSQL);
        }
      }
    }
    // 执行创建语句
    dao.execute(sqls.toArray(new Sql[sqls.size()]));
  }

  public void formatQuery(DaoStatement daoStatement) {
    if (daoStatement == null) return;
    SqlContext ctx = daoStatement.getContext();
    if (ctx == null || ctx.getPager() == null) return;
    if (daoStatement instanceof Pojo) formatQuery((Pojo) daoStatement);
    else if (daoStatement instanceof Sql) formatQuery((Sql) daoStatement);
    else throw Lang.noImplement();
  }

  public abstract void formatQuery(Pojo pojo);

  public void formatQuery(Sql sql) {
    throw Lang.noImplement();
  }

  public Pojo fetchPojoId(Entity<?> en, MappingField idField) {
    String autoSql = "SELECT MAX($field) AS $field FROM $view";
    Pojo autoInfo = new SqlFieldMacro(idField, autoSql);
    autoInfo.setEntity(en);
    return autoInfo;
  }

  public boolean isSupportAutoIncrement() {
    return true;
  }

  public String makePksName(Entity<?> en) {
    String name = en.getType().getAnnotation(PK.class).name();
    if (Strings.isBlank(name)) {
      StringBuilder sb = new StringBuilder();
      for (MappingField mf : en.getPks()) {
        sb.append("_").append(mf.getColumnName());
      }
      sb.setLength(sb.length() - 1);
      return sb.toString();
    }
    return name;
  }

  public void addDefaultValue(StringBuilder sb, MappingField mf) {
    if (!mf.hasDefaultValue()) return;
    if (mf.getTypeMirror().isNumber()) sb.append(" DEFAULT ").append(getDefaultValue(mf));
    else sb.append(" DEFAULT '").append(getDefaultValue(mf)).append('\'');
  }

  public boolean addColumnNeedColumn() {
    return true;
  }

  public boolean supportTimestampDefault() {
    return true;
  }

  public void setKeywords(Set<String> keywords) {
    this.keywords = keywords;
  }

  public Set<String> getKeywords() {
    return keywords;
  }

  public String wrapKeywork(String columnName, boolean force) {
    if (force || keywords.contains(columnName.toUpperCase())) return "`" + columnName + "`";
    return null;
  }

  public boolean isSupportGeneratedKeys() {
    return true;
  }
}