PageRenderTime 45ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/dumbhippo/branches/production/server/src/com/dumbhippo/server/blocks/AbstractBlockHandlerBean.java

https://gitlab.com/manoj-makkuboy/magnetism
Java | 343 lines | 222 code | 47 blank | 74 comment | 22 complexity | cd7d7a0fa05e187637e77cfb9d33d4d6 MD5 | raw file
  1. package com.dumbhippo.server.blocks;
  2. import java.lang.reflect.Constructor;
  3. import java.lang.reflect.InvocationTargetException;
  4. import java.util.Collections;
  5. import java.util.Set;
  6. import javax.ejb.EJB;
  7. import javax.persistence.EntityManager;
  8. import javax.persistence.PersistenceContext;
  9. import org.jboss.annotation.IgnoreDependency;
  10. import org.slf4j.Logger;
  11. import com.dumbhippo.GlobalSetup;
  12. import com.dumbhippo.persistence.Block;
  13. import com.dumbhippo.persistence.ExternalAccountType;
  14. import com.dumbhippo.persistence.Group;
  15. import com.dumbhippo.persistence.GroupBlockData;
  16. import com.dumbhippo.persistence.StackInclusion;
  17. import com.dumbhippo.persistence.User;
  18. import com.dumbhippo.persistence.UserBlockData;
  19. import com.dumbhippo.server.ChatSystem;
  20. import com.dumbhippo.server.ExternalAccountSystem;
  21. import com.dumbhippo.server.GroupSystem;
  22. import com.dumbhippo.server.IdentitySpider;
  23. import com.dumbhippo.server.NotFoundException;
  24. import com.dumbhippo.server.PersonViewer;
  25. import com.dumbhippo.server.Stacker;
  26. import com.dumbhippo.server.util.EJBUtil;
  27. import com.dumbhippo.server.views.PersonView;
  28. import com.dumbhippo.server.views.SystemViewpoint;
  29. import com.dumbhippo.server.views.UserViewpoint;
  30. import com.dumbhippo.server.views.Viewpoint;
  31. public abstract class AbstractBlockHandlerBean<BlockViewSubType extends BlockView> implements BlockHandler {
  32. static private final Logger logger = GlobalSetup.getLogger(AbstractBlockHandlerBean.class);
  33. @PersistenceContext(unitName = "dumbhippo")
  34. protected EntityManager em;
  35. @EJB
  36. protected ChatSystem chatSystem;
  37. @EJB
  38. protected IdentitySpider identitySpider;
  39. @EJB
  40. protected GroupSystem groupSystem;
  41. @EJB
  42. protected ExternalAccountSystem externalAccountSystem;
  43. @EJB
  44. protected PersonViewer personViewer;
  45. @EJB
  46. @IgnoreDependency
  47. protected Stacker stacker;
  48. private Class<? extends BlockViewSubType> viewClass;
  49. private Constructor<? extends BlockViewSubType> viewClassConstructorUser;
  50. private Constructor<? extends BlockViewSubType> viewClassConstructorGroup;
  51. protected AbstractBlockHandlerBean(Class<? extends BlockViewSubType> viewClass) {
  52. this.viewClass = viewClass;
  53. try {
  54. this.viewClassConstructorUser = viewClass.getConstructor(Viewpoint.class, Block.class, UserBlockData.class, boolean.class);
  55. } catch (SecurityException e) {
  56. } catch (NoSuchMethodException e) {
  57. }
  58. try {
  59. this.viewClassConstructorGroup = viewClass.getConstructor(Viewpoint.class, Block.class, GroupBlockData.class, boolean.class);
  60. } catch (SecurityException e) {
  61. } catch (NoSuchMethodException e) {
  62. }
  63. if (this.viewClassConstructorUser == null || this.viewClassConstructorGroup == null)
  64. logger.debug("{} must override createBlockView since it lacks the expected constructors for its view class", this.getClass().getName());
  65. }
  66. private void checkCreationInvariants(Viewpoint viewpoint, Block block) throws BlockNotVisibleException {
  67. UserViewpoint userview = null;
  68. if (viewpoint instanceof UserViewpoint)
  69. userview = (UserViewpoint) viewpoint;
  70. if (block.getInclusion() == StackInclusion.ONLY_WHEN_VIEWING_SELF) {
  71. User user = identitySpider.lookupUser(block.getData1AsGuid());
  72. if (userview == null || !userview.getViewer().equals(user)) {
  73. // FIXME should this be a RuntimeException? logger.warn is here so we can investigate
  74. // that if the exception ever really happens
  75. logger.warn("Trying to view an ONLY_WHEN_VIEWING_SELF block from a different viewpoint: {} block={}", userview, block);
  76. throw new BlockNotVisibleException("ONLY_WHEN_VIEWING_SELF block is not visible to non-self viewpoint");
  77. }
  78. }
  79. }
  80. public BlockViewSubType getUnpopulatedBlockView(Viewpoint viewpoint, Block block,
  81. UserBlockData ubd, boolean participated) throws BlockNotVisibleException {
  82. checkCreationInvariants(viewpoint, block);
  83. BlockViewSubType blockView = createBlockView(viewpoint, block, ubd, participated);
  84. checkBlockViewVisible(blockView);
  85. return blockView;
  86. }
  87. public BlockViewSubType getUnpopulatedBlockView(Viewpoint viewpoint, Block block,
  88. GroupBlockData gbd, boolean participated) throws BlockNotVisibleException {
  89. checkCreationInvariants(viewpoint, block);
  90. BlockViewSubType blockView = createBlockView(viewpoint, block, gbd, participated);
  91. checkBlockViewVisible(blockView);
  92. return blockView;
  93. }
  94. /**
  95. * Creates a new block view. This should just create the object, not fill it in at all.
  96. * There are two later stages for filling it in; checkBlockViewVisible() will be called
  97. * to see if the viewpoint can view the block view, and then populateBlockViewImpl()
  98. * will be called to initialize any additional details on the block view if it is
  99. * visible.
  100. *
  101. * The default implementation just constructs an instance of viewClass.
  102. *
  103. * @param viewpoint
  104. * @param block
  105. * @param ubd
  106. * @return new block view
  107. */
  108. protected BlockViewSubType createBlockView(Viewpoint viewpoint, Block block,
  109. UserBlockData ubd, boolean participated) {
  110. if (viewClassConstructorUser == null)
  111. throw new IllegalStateException("Must override createBlockView if your block view type doesn't have the right constructor");
  112. try {
  113. return viewClassConstructorUser.newInstance(viewpoint, block, ubd, participated);
  114. } catch (IllegalArgumentException e) {
  115. throw new RuntimeException(e);
  116. } catch (InstantiationException e) {
  117. throw new RuntimeException(e);
  118. } catch (IllegalAccessException e) {
  119. throw new RuntimeException(e);
  120. } catch (InvocationTargetException e) {
  121. throw new RuntimeException(e);
  122. }
  123. }
  124. protected BlockViewSubType createBlockView(Viewpoint viewpoint, Block block,
  125. GroupBlockData gbd, boolean participated) {
  126. if (viewClassConstructorUser == null)
  127. throw new IllegalStateException("Must override createBlockView if your block view type doesn't have the right constructor");
  128. try {
  129. return viewClassConstructorGroup.newInstance(viewpoint, block, gbd, participated);
  130. } catch (IllegalArgumentException e) {
  131. throw new RuntimeException(e);
  132. } catch (InstantiationException e) {
  133. throw new RuntimeException(e);
  134. } catch (IllegalAccessException e) {
  135. throw new RuntimeException(e);
  136. } catch (InvocationTargetException e) {
  137. throw new RuntimeException(e);
  138. }
  139. }
  140. /**
  141. * The default implementation of this returns immediately if block.isPublicBlock(), otherwise
  142. * tries to call populateBlockViewImpl() and lets that throw BlockNotVisibleException if appropriate.
  143. * Subclasses may be able to do something more efficient than a full populateBlockViewImpl().
  144. *
  145. * @param blockView the block view which may or may not be visible to its viewpoint
  146. * @throws BlockNotVisibleException if blockView's viewpoint can't see this blockView
  147. */
  148. protected void checkBlockViewVisible(BlockViewSubType blockView) throws BlockNotVisibleException {
  149. Block block = blockView.getBlock();
  150. if (!block.isPublicBlock()) {
  151. populateBlockViewImpl(blockView); // throws if we can't see the block contents
  152. }
  153. }
  154. /**
  155. * Fill in a block view. Called by the default implementation of checkBlockViewVisible() and also
  156. * by the default implementation of populateBlockView() - thus may be called twice. The second
  157. * call will be skipped if blockView.isPopulated(), so set that flag once you fully populate.
  158. *
  159. * @param blockView a block view
  160. * @throws BlockNotVisibleException if the block view is not visible to its viewpoint
  161. */
  162. protected abstract void populateBlockViewImpl(BlockViewSubType blockView)
  163. throws BlockNotVisibleException;
  164. // this is final because you need to override populateBlockViewImpl instead.
  165. public final void populateBlockView(BlockView blockView) {
  166. try {
  167. if (!blockView.isPopulated())
  168. populateBlockViewImpl(viewClass.cast(blockView));
  169. } catch (BlockNotVisibleException e) {
  170. logger.warn("populateBlockView() should not run into a BlockNotVisibleException because prepareBlockView() should have done it {}",
  171. blockView);
  172. throw new RuntimeException("prepareBlockView missed a visibility check", e);
  173. }
  174. }
  175. private Set<User> getUsersWhoCareAboutData1User(Block block, User user) {
  176. Set<User> peopleWhoCare = null;
  177. switch (block.getInclusion()) {
  178. case IN_ALL_STACKS:
  179. case ONLY_WHEN_VIEWED_BY_OTHERS:
  180. peopleWhoCare = identitySpider.getUsersWhoHaveUserAsContact(SystemViewpoint.getInstance(), user);
  181. // we also show each block to its "owner" when it is IN_ALL_STACKS;
  182. // we include the "owner" for the ONLY_WHEN_VIEWED_BY_OTHERS block, so
  183. // that the block is displayed in the owner's mugshot when it is viewed
  184. // by another person
  185. peopleWhoCare.add(user);
  186. return peopleWhoCare;
  187. case ONLY_WHEN_VIEWING_SELF:
  188. peopleWhoCare = Collections.singleton(user);
  189. return peopleWhoCare;
  190. // no default, it hides bugs
  191. }
  192. throw new RuntimeException("invalid inclusion " + block);
  193. }
  194. protected User getData1User(Block block) {
  195. User user;
  196. try {
  197. user = EJBUtil.lookupGuid(em, User.class, block.getData1AsGuid());
  198. } catch (NotFoundException e) {
  199. throw new RuntimeException("invalid user in data1 of " + block, e);
  200. }
  201. return user;
  202. }
  203. protected PersonView getData1UserView(Viewpoint viewpoint, Block block) {
  204. User user = getData1User(block);
  205. // No PersonViewExtra are needed since we know this isn't a contact so we have a name
  206. // without having to get any resources.
  207. PersonView userView = personViewer.getPersonView(viewpoint, user);
  208. return userView;
  209. }
  210. /**
  211. * Utility helper for implementing getInterestedUsers() that gets everyone with
  212. * the user id in data1 listed in their contacts.
  213. *
  214. * Returns only the person themselves in the set if block.getInclusion() == ONLY_WHEN_VIEWING_SELF.
  215. *
  216. * @param block
  217. * @return
  218. */
  219. protected final Set<User> getUsersWhoCareAboutData1User(Block block) {
  220. return getUsersWhoCareAboutData1User(block, getData1User(block));
  221. }
  222. protected final Set<User> getUsersWhoCareAboutData1UserAndExternalAccount(Block block, ExternalAccountType accountType) {
  223. User user = getData1User(block);
  224. if (externalAccountSystem.getExternalAccountExistsLovedAndEnabled(SystemViewpoint.getInstance(), user, accountType)) {
  225. return getUsersWhoCareAboutData1User(block, user);
  226. } else {
  227. return Collections.emptySet();
  228. }
  229. }
  230. /**
  231. * Utility helper for implementing getInterestedUsers() that gets everyone in
  232. * the group identified by the group id in data1.
  233. *
  234. * @param block
  235. * @return
  236. */
  237. protected final Set<User> getUsersWhoCareAboutData1Group(Block block) {
  238. Group group;
  239. try {
  240. group = EJBUtil.lookupGuid(em, Group.class, block.getData1AsGuid());
  241. } catch (NotFoundException e) {
  242. throw new RuntimeException("invalid group in data1 of " + block, e);
  243. }
  244. Set<User> groupMembers = groupSystem.getUserMembers(SystemViewpoint.getInstance(), group);
  245. return groupMembers;
  246. }
  247. /**
  248. * Utility helper for implementing getInterestedGroups() that returns
  249. * a single-member set with the group stored in data1.
  250. *
  251. * @param block
  252. * @return
  253. */
  254. protected Set<Group> getData1GroupAsSet(Block block) {
  255. Group group;
  256. try {
  257. group = EJBUtil.lookupGuid(em, Group.class, block.getData1AsGuid());
  258. } catch (NotFoundException e) {
  259. throw new RuntimeException(e);
  260. }
  261. return Collections.singleton(group);
  262. }
  263. private Set<Group> getGroupsData1UserIsIn(Block block, User user) {
  264. switch (block.getInclusion()) {
  265. case IN_ALL_STACKS:
  266. case ONLY_WHEN_VIEWED_BY_OTHERS:
  267. return groupSystem.findRawGroups(SystemViewpoint.getInstance(), user);
  268. case ONLY_WHEN_VIEWING_SELF:
  269. return Collections.emptySet();
  270. // no default, hides bugs
  271. }
  272. throw new RuntimeException("invalid inclusion " + block);
  273. }
  274. /**
  275. * Utility helper for implementing getInterestedGroups() that returns
  276. * the set of groups the user id stored in data1 is a member of.
  277. *
  278. * Returns an empty set of groups if the block's inclusion is
  279. * ONLY_WHEN_VIEWING_SELF.
  280. *
  281. * @param block
  282. * @return
  283. */
  284. protected final Set<Group> getGroupsData1UserIsIn(Block block) {
  285. User user = getData1User(block);
  286. return getGroupsData1UserIsIn(block, user);
  287. }
  288. protected final Set<Group> getGroupsData1UserIsInIfExternalAccount(Block block, ExternalAccountType accountType) {
  289. User user = getData1User(block);
  290. if (externalAccountSystem.getExternalAccountExistsLovedAndEnabled(SystemViewpoint.getInstance(), user, accountType)) {
  291. return getGroupsData1UserIsIn(block, user);
  292. } else {
  293. return Collections.emptySet();
  294. }
  295. }
  296. }