package open.dolphin.session; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import javax.annotation.Resource; import javax.ejb.SessionContext; import javax.ejb.Stateless; import javax.inject.Named; import javax.persistence.EntityManager; import javax.persistence.NoResultException; import javax.persistence.PersistenceContext; import open.dolphin.infomodel.*; /** * * @author kazushi, Minagawa, Digital Globe, Inc. */ @Named @Stateless public class StampServiceBean { private static final String QUERY_TREE_BY_USER_PK = "from StampTreeModel s where s.user.id=:userPK"; private static final String QUERY_SUBSCRIBED_BY_USER_PK = "from SubscribedTreeModel s where s.user.id=:userPK"; private static final String QUERY_LOCAL_PUBLISHED_TREE = "from PublishedTreeModel p where p.publishType=:fid"; private static final String QUERY_PUBLIC_TREE = "from PublishedTreeModel p where p.publishType='global'"; private static final String QUERY_PUBLISHED_TREE_BY_ID = "from PublishedTreeModel p where p.id=:id"; private static final String QUERY_SUBSCRIBED_BY_USER_PK_TREE_ID = "from SubscribedTreeModel s where s.user.id=:userPK and s.treeId=:treeId"; private static final String EXCEPTION_FIRST_COMMIT_WIN = "First Commit Win Exception"; private static final String USER_PK = "userPK"; private static final String FID = "fid"; private static final String TREE_ID = "treeId"; private static final String ID = "id"; @Resource private SessionContext ctx; @PersistenceContext private EntityManager em; private int getNextVersion(String holdVersion, String dbVersion) { int newVersion = -1; if (holdVersion!=null && dbVersion!=null) { // 先勝ち 保持しているVersion=DB Version if (holdVersion.equals(dbVersion)) { newVersion = Integer.parseInt(holdVersion)+1; // +1 } } else if (holdVersion==null && dbVersion!=null) { // あってはいけない } else if (holdVersion!=null && dbVersion==null) { // あってはいけない } else if (holdVersion==null && dbVersion==null) { // 両方とも存在しないケース: 新規にTreeが保存される時 newVersion = 0; } return newVersion; } /** * user個人のStampTreeを保存/更新する。 * @param model 保存する StampTree * @return id */ public long putTree(StampTreeModel model) { int vesion; try { StampTreeModel exist = (StampTreeModel) em.createQuery(QUERY_TREE_BY_USER_PK) .setParameter(USER_PK, model.getUserModel().getId()) .getSingleResult(); vesion = getNextVersion(model.getVersionNumber(), exist.getVersionNumber()); } catch (NoResultException e) { vesion = 0; } if (vesion>=0) { // 保存 model.setVersionNumber(String.valueOf(vesion)); StampTreeModel saveOrUpdate = em.merge(model); return saveOrUpdate.getId(); } else { throw new RuntimeException(EXCEPTION_FIRST_COMMIT_WIN); } } // pk,versionNumber public String syncTree(StampTreeModel model) { int vesion; try { StampTreeModel exist = (StampTreeModel) em.createQuery(QUERY_TREE_BY_USER_PK) .setParameter(USER_PK, model.getUserModel().getId()) .getSingleResult(); vesion = getNextVersion(model.getVersionNumber(), exist.getVersionNumber()); } catch (NoResultException e) { vesion = 0; } if (vesion>=0) { // 保存 model.setVersionNumber(String.valueOf(vesion)); StampTreeModel saveOrUpdate = em.merge(model); StringBuilder sb = new StringBuilder(); sb.append(String.valueOf(saveOrUpdate.getId())).append(",").append(saveOrUpdate.getVersionNumber()); return sb.toString(); } else { throw new RuntimeException(EXCEPTION_FIRST_COMMIT_WIN); } } // pk,versionNumber public void forceSyncTree(StampTreeModel model) { em.merge(model); } /** * User個人及びサブスクライブしているTreeを取得する。 * @param userPk userId(DB key) * @return User個人及びサブスクライブしているTreeのリスト */ public StampTreeHolder getTrees(long userPK) { StampTreeHolder ret = new StampTreeHolder(); //----------------------------------- // パーソナルツリーを取得する //----------------------------------- List<StampTreeModel> list = (List<StampTreeModel>) em.createQuery(QUERY_TREE_BY_USER_PK) .setParameter(USER_PK, userPK) .getResultList(); // 新規ユーザの場合 if (list.isEmpty()) { return ret; } // 最初の Tree を追加 StampTreeModel st = (StampTreeModel)list.remove(0); ret.setPersonalTree(st); // まだある場合 BUG if (list.size() > 0) { // 後は delete する for (int i=0; i < list.size(); i++) { st = (StampTreeModel) list.remove(0); em.remove(st); } } //-------------------------------------------------- // ユーザがサブスクライブしているStampTreeのリストを取得する //-------------------------------------------------- List<SubscribedTreeModel> subscribed = (List<SubscribedTreeModel>)em.createQuery(QUERY_SUBSCRIBED_BY_USER_PK) .setParameter(USER_PK, userPK) .getResultList(); HashMap tmp = new HashMap(5, 0.8f); for (SubscribedTreeModel sm : subscribed) { // BUG 重複をチェックする if (tmp.get(sm.getTreeId()) == null) { // まだ存在しない場合 tmp.put(sm.getTreeId(), "A"); try { PublishedTreeModel published = (PublishedTreeModel)em.find(PublishedTreeModel.class, sm.getTreeId()); if (published != null) { ret.addSubscribedTree(published); } else { em.remove(sm); } } catch (NoResultException e) { em.remove(sm); } } else { // 重複してインポートしている場合に削除する em.remove(sm); } } return ret; } // version public String updatePublishedTree(StampTreeHolder h) { // 個人Tree StampTreeModel st = (StampTreeModel)h.getPersonalTree(); // 公開Tree PublishedTreeModel pt = (PublishedTreeModel)h.getSubscribedList().get(0); //----------------------------------------------------------------------- // 個人Treeがsyncできないといけない //----------------------------------------------------------------------- int vesion; try { StampTreeModel exist = (StampTreeModel) em.createQuery(QUERY_TREE_BY_USER_PK) .setParameter(USER_PK, st.getUserModel().getId()) .getSingleResult(); vesion = getNextVersion(st.getVersionNumber(), exist.getVersionNumber()); } catch (NoResultException e) { vesion = 0; } if (vesion>=0) { // 保存 st.setVersionNumber(String.valueOf(vesion)); StampTreeModel saveOrUpdate = em.merge(st); if (pt.getId()==0L) { pt.setId(st.getId()); em.persist(pt); } else { em.merge(pt); } // versionNum return saveOrUpdate.getVersionNumber(); } else { throw new RuntimeException(EXCEPTION_FIRST_COMMIT_WIN); } } /** * 公開したTreeを削除する。 * @param id 削除するTreeのId * @return VersionNumber */ public String cancelPublishedTree(StampTreeModel st) { //----------------------------------------------------------------------- // 個人Treeがsyncできないといけない //----------------------------------------------------------------------- int vesion; try { StampTreeModel exist = (StampTreeModel) em.createQuery(QUERY_TREE_BY_USER_PK) .setParameter(USER_PK, st.getUserModel().getId()) .getSingleResult(); vesion = getNextVersion(st.getVersionNumber(), exist.getVersionNumber()); } catch (NoResultException e) { vesion = 0; } if (vesion>=0) { // 保存 st.setVersionNumber(String.valueOf(vesion)); StampTreeModel saveOrUpdate = em.merge(st); //------------------------ // 公開Treeを削除する //------------------------ List<PublishedTreeModel> list = em.createQuery(QUERY_PUBLISHED_TREE_BY_ID) .setParameter(ID, st.getId()) .getResultList(); for (PublishedTreeModel m : list) { em.remove(m); } // versionNum return saveOrUpdate.getVersionNumber(); } else { throw new RuntimeException(EXCEPTION_FIRST_COMMIT_WIN); } } /** * 公開されているStampTreeのリストを取得する。 * @return ローカル及びパブリックTreeのリスト */ public List<PublishedTreeModel> getPublishedTrees(String fid) { // ログインユーザの施設IDを取得する //String fid = SessionHelper.getCallersFacilityId(ctx); List<PublishedTreeModel> ret = new ArrayList<PublishedTreeModel>(); // local に公開されているTreeを取得する // publishType=施設ID List locals = em.createQuery(QUERY_LOCAL_PUBLISHED_TREE) .setParameter(FID, fid) .getResultList(); ret.addAll((List<PublishedTreeModel>) locals); // パブリックTeeを取得する List publics = em.createQuery(QUERY_PUBLIC_TREE) .getResultList(); ret.addAll((List<PublishedTreeModel>) publics); return ret; } /** * 公開Treeにサブスクライブする。 * @param addList サブスクライブする * @return */ public List<Long> subscribeTrees(List<SubscribedTreeModel> addList) { List<Long> ret = new ArrayList<Long>(); for (SubscribedTreeModel model : addList) { em.persist(model); ret.add(new Long(model.getId())); } return ret; } /** * 公開Treeにアンサブスクライブする。 * @param ids アンサブスクライブするTreeのIdリスト * @return */ public int unsubscribeTrees(List<Long> list) { int cnt = 0; int len = list.size(); for (int i = 0; i < len; i+=2) { Long treeId = list.get(i); Long userPK = list.get(i+1); List<SubscribedTreeModel> removes = (List<SubscribedTreeModel>) em.createQuery(QUERY_SUBSCRIBED_BY_USER_PK_TREE_ID) .setParameter(USER_PK, userPK) .setParameter(TREE_ID, treeId) .getResultList(); for (SubscribedTreeModel sm : removes) { em.remove(sm); } cnt++; } return cnt; } /** * Stampを保存する。 * @param model StampModel * @return 保存件数 */ public List<String> putStamp(List<StampModel> list) { List<String> ret = new ArrayList<String>(); for (StampModel model : list) { em.persist(model); ret.add(model.getId()); } return ret; } /** * Stampを保存する。 * @param model StampModel * @return 保存件数 */ public String putStamp(StampModel model) { //em.persist(model); em.merge(model); return model.getId(); } /** * Stampを取得する。 * @param stampId 取得する StampModel の id * @return StampModel */ public StampModel getStamp(String stampId) { try { return (StampModel) em.find(StampModel.class, stampId); } catch (NoResultException e) { } return null; } /** * Stampを取得する。 * @param stampId 取得する StampModel の id * @return StampModel */ public List<StampModel> getStamp(List<String> ids) { List<StampModel> ret = new ArrayList<StampModel>(); try { for (String stampId : ids) { StampModel test = (StampModel) em.find(StampModel.class, stampId); ret.add(test); } } catch (Exception e) { } return ret; } /** * Stampを削除する。 * @param stampId 削除する StampModel の id * @return 削除件数 */ public int removeStamp(String stampId) { StampModel exist = (StampModel) em.find(StampModel.class, stampId); em.remove(exist); return 1; } /** * Stampを削除する。 * @param stampId 削除する StampModel の id List * @return 削除件数 */ public int removeStamp(List<String> ids) { int cnt =0; for (String stampId : ids) { StampModel exist = (StampModel) em.find(StampModel.class, stampId); em.remove(exist); cnt++; } return cnt; } }