@Override public void revertInstanceFromTrash(Long entityId, Long instanceId) { EntityDto entity = getEntity(entityId); validateCredentials(entity); validateNonEditableProperty(entity); MotechDataService service = getServiceForEntity(entity); Object trash = service.findTrashInstanceById(instanceId, entityId); List<FieldRecord> fieldRecords = new LinkedList<>(); try { for (FieldDto field : entityService.getEntityFields(entity.getId())) { if (ID_FIELD_NAME.equalsIgnoreCase(field.getBasic().getDisplayName())) { continue; } Field f = FieldUtils.getField( trash.getClass(), StringUtils.uncapitalize(field.getBasic().getName()), true); FieldRecord record = new FieldRecord(field); record.setValue(f.get(trash)); fieldRecords.add(record); } Class<?> entityClass = getEntityClass(entity); Object newInstance = entityClass.newInstance(); updateFields(newInstance, fieldRecords, service, null); service.revertFromTrash(newInstance, trash); } catch (Exception e) { throw new RevertFromTrashException(entity.getName(), instanceId, e); } }
@Test public void shouldUseCorrectClassLoaderWhenCreatingInstances() throws ClassNotFoundException { mockSampleFields(); mockEntity(); mockDataService(); Bundle ddeBundle = mock(Bundle.class); Bundle entitiesBundle = mock(Bundle.class); when(bundleContext.getBundles()).thenReturn(new Bundle[] {ddeBundle, entitiesBundle}); when(entity.getBundleSymbolicName()).thenReturn("org.motechproject.test"); when(entitiesBundle.getSymbolicName()) .thenReturn(Constants.BundleNames.MDS_ENTITIES_SYMBOLIC_NAME); when(ddeBundle.getSymbolicName()).thenReturn("org.motechproject.test"); Class testClass = TestSample.class; when(entitiesBundle.loadClass(testClass.getName())).thenReturn(testClass); when(ddeBundle.loadClass(testClass.getName())).thenReturn(testClass); EntityRecord entityRecord = new EntityRecord(null, ENTITY_ID, Collections.<FieldRecord>emptyList()); when(entity.isDDE()).thenReturn(true); instanceService.saveInstance(entityRecord); verify(ddeBundle).loadClass(TestSample.class.getName()); when(entity.isDDE()).thenReturn(false); instanceService.saveInstance(entityRecord); verify(entitiesBundle).loadClass(TestSample.class.getName()); verify(motechDataService, times(2)).create(any(TestSample.class)); }
private EntityRecord instanceToRecord( Object instance, EntityDto entityDto, List<FieldDto> fields, MotechDataService service) { if (instance == null) { return null; } try { List<FieldRecord> fieldRecords = new ArrayList<>(); for (FieldDto field : fields) { Object value = getProperty(instance, field, service); Object displayValue = getDisplayValueForField(field, value); value = parseValueForDisplay(value, field.getMetadata(Constants.MetadataKeys.RELATED_FIELD)); FieldRecord fieldRecord = new FieldRecord(field); fieldRecord.setValue(value); fieldRecord.setDisplayValue(displayValue); fieldRecords.add(fieldRecord); } Number id = (Number) PropertyUtil.safeGetProperty(instance, ID_FIELD_NAME); return new EntityRecord(id == null ? null : id.longValue(), entityDto.getId(), fieldRecords); } catch (Exception e) { throw new ObjectReadException(entityDto.getName(), e); } }
@Override public long countTrashRecords(Long entityId) { EntityDto entity = getEntity(entityId); validateCredentialsForReading(entity); return trashService.countTrashRecords(entity.getClassName()); }
@Override @Transactional public <T> Records<T> getRelatedFieldValue( Long entityId, Long instanceId, String fieldName, QueryParams queryParams) { EntityDto entity = getEntity(entityId); validateCredentials(entity); String entityName = entity.getName(); MotechDataService service = getServiceForEntity(entity); Object instance = service.findById(instanceId); if (instance == null) { throw new ObjectNotFoundException(entityName, instanceId); } try { Collection<T> relatedAsColl = TypeHelper.asCollection(PropertyUtil.getProperty(instance, fieldName)); List<T> filtered = InMemoryQueryFilter.filter(relatedAsColl, queryParams); int recordCount = relatedAsColl.size(); int rowCount = (int) Math.ceil(recordCount / (double) queryParams.getPageSize()); return new Records<>(queryParams.getPage(), rowCount, recordCount, filtered); } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { throw new ObjectReadException(entityName, e); } }
@Test(expected = EntityInstancesNonEditableException.class) public void shouldThrowExceptionWhileDeletingInstanceInNonEditableEntity() { EntityDto nonEditableEntity = new EntityDto(); nonEditableEntity.setNonEditable(true); when(entityService.getEntity(ANOTHER_ENTITY_ID)).thenReturn(nonEditableEntity); instanceService.deleteInstance(ANOTHER_ENTITY_ID, INSTANCE_ID); }
@Override public void revertPreviousVersion(Long entityId, Long instanceId, Long historyId) { validateNonEditableProperty(getEntity(entityId)); HistoryRecord historyRecord = getHistoryRecord(entityId, instanceId, historyId); if (!historyRecord.isRevertable()) { EntityDto entity = getEntity(entityId); throw new EntitySchemaMismatchException(entity.getName()); } saveInstance(new EntityRecord(instanceId, entityId, historyRecord.getFields())); }
@Override public List<EntityRecord> getTrashRecords(Long entityId, QueryParams queryParams) { EntityDto entity = getEntity(entityId); validateCredentialsForReading(entity); MotechDataService service = getServiceForEntity(entity); List<FieldDto> fields = entityService.getEntityFields(entityId); Collection collection = trashService.getInstancesFromTrash(entity.getClassName(), queryParams); return instancesToRecords(collection, entity, fields, service); }
private void validateCredentials(EntityDto entity) { boolean authorized; SecurityMode securityMode = entity.getSecurityMode(); if (securityMode != null) { Set<String> securityMembers = entity.getSecurityMembers(); authorized = entity.hasAccessToEntityFromSecurityMode(securityMode, securityMembers); if (!authorized && !securityMode.isInstanceRestriction()) { throw new SecurityException(); } } }
@Test(expected = EntityInstancesNonEditableException.class) public void shouldThrowExceptionWhileSavingInstanceInNonEditableEntity() { EntityDto nonEditableEntity = new EntityDto(); nonEditableEntity.setNonEditable(true); nonEditableEntity.setId(ANOTHER_ENTITY_ID); EntityRecord entityRecord = new EntityRecord(null, ANOTHER_ENTITY_ID, new ArrayList<FieldRecord>()); when(entityService.getEntity(ANOTHER_ENTITY_ID)).thenReturn(nonEditableEntity); instanceService.saveInstance(entityRecord); }
private void mockAnotherEntity() { EntityDto entityWithRelatedField = mock(EntityDto.class); when(entityService.getEntity(ANOTHER_ENTITY_ID)).thenReturn(entityWithRelatedField); when(entityWithRelatedField.getClassName()).thenReturn(AnotherSample.class.getName()); when(entityWithRelatedField.getName()).thenReturn(AnotherSample.class.getSimpleName()); ServiceReference serviceReferenceForAnotherSample = mock(ServiceReference.class); when(bundleContext.getServiceReference( ClassName.getInterfaceName(AnotherSample.class.getName()))) .thenReturn(serviceReferenceForAnotherSample); when(bundleContext.getService(serviceReferenceForAnotherSample)) .thenReturn(serviceForAnotherSample); }
@Test(expected = SecurityException.class) public void shouldThrowExceptionWhileReadingInstanceWithoutAnyPermission() { EntityDto entityDto = new EntityDto(); entityDto.setReadOnlySecurityMode(SecurityMode.NO_ACCESS); entityDto.setSecurityMode(SecurityMode.NO_ACCESS); EntityRecord entityRecord = new EntityRecord(ANOTHER_ENTITY_ID, null, new ArrayList<FieldRecord>()); when(entityService.getEntity(ANOTHER_ENTITY_ID)).thenReturn(entityDto); instanceService.getEntityRecords(entityRecord.getId()); }
private void validateCredentialsForReading(EntityDto entity) { boolean authorized = false; SecurityMode securityMode = entity.getSecurityMode(); SecurityMode readOnlySecurityMode = entity.getReadOnlySecurityMode(); if (securityMode != null) { Set<String> securityMembers = entity.getSecurityMembers(); authorized = entity.hasAccessToEntityFromSecurityMode(securityMode, securityMembers); if (!authorized) { if (readOnlySecurityMode != null) { Set<String> readOnlySecurityMembers = entity.getReadOnlySecurityMembers(); authorized = entity.hasAccessToEntityFromSecurityMode( readOnlySecurityMode, readOnlySecurityMembers); if (isAuthorizedByReadAccessOrIsInstanceRestriction( authorized, readOnlySecurityMode, securityMode)) { throw new SecurityException(); } } } } if (!authorized && readOnlySecurityMode != null) { Set<String> readOnlySecurityMembers = entity.getReadOnlySecurityMembers(); authorized = entity.hasAccessToEntityFromSecurityMode(readOnlySecurityMode, readOnlySecurityMembers); if (!authorized && !readOnlySecurityMode.isInstanceRestriction()) { throw new SecurityException(); } } }
@Test public void shouldLoadBlobField() throws InstanceNotFoundException { EntityDto entityDto = new EntityDto(); entityDto.setReadOnlySecurityMode(null); entityDto.setSecurityMode(null); entityDto.setClassName(TestSample.class.getName()); when(entityService.getEntity(ENTITY_ID + 1)).thenReturn(entityDto); mockDataService(); TestSample instance = Mockito.mock(TestSample.class); when(motechDataService.findById(ENTITY_ID + 1)).thenReturn(instance); instanceService.getInstanceField(12l, ENTITY_ID + 1, "blobField"); verify(motechDataService).getDetachedField(instance, "blobField"); }
@Override public EntityRecord getEntityInstance(Long entityId, Long instanceId) { EntityDto entity = getEntity(entityId); validateCredentialsForReading(entity); MotechDataService service = getServiceForEntity(entity); Object instance = service.retrieve(ID_FIELD_NAME, instanceId); if (instance == null) { throw new ObjectNotFoundException(entity.getName(), instanceId); } List<FieldDto> fields = entityService.getEntityFields(entityId); return instanceToRecord(instance, entity, fields, service); }
@Test public void shouldAcceptUserWithNoPermissionWhileReadingInstanceWithNoSecurityMode() { EntityDto entityDto = new EntityDto(); entityDto.setReadOnlySecurityMode(null); entityDto.setSecurityMode(null); entityDto.setClassName(TestSample.class.getName()); EntityRecord entityRecord = new EntityRecord(ANOTHER_ENTITY_ID, null, new ArrayList<>()); when(entityService.getEntity(ANOTHER_ENTITY_ID)).thenReturn(entityDto); mockDataService(); instanceService.getEntityRecords(entityRecord.getId()); verify(entityService).getEntityFieldsForUI(ANOTHER_ENTITY_ID); }
@Override @Transactional public Object saveInstance(EntityRecord entityRecord, Long deleteValueFieldId) { EntityDto entity = getEntity(entityRecord.getEntitySchemaId()); validateCredentials(entity); validateNonEditableProperty(entity); List<FieldDto> entityFields = getEntityFields(entityRecord.getEntitySchemaId()); try { MotechDataService service = getServiceForEntity(entity); Class<?> entityClass = getEntityClass(entity); boolean newObject = entityRecord.getId() == null; Object instance; if (newObject) { instance = entityClass.newInstance(); for (FieldDto entityField : entityFields) { if (entityField.getType().isMap() && entityField.getBasic().getDefaultValue() != null) { setInstanceFieldMap(instance, entityField); } } } else { instance = service.retrieve(ID_FIELD_NAME, entityRecord.getId()); if (instance == null) { throw new ObjectNotFoundException(entity.getName(), entityRecord.getId()); } } updateFields(instance, entityRecord.getFields(), service, deleteValueFieldId, !newObject); if (newObject) { return service.create(instance); } else { return service.update(instance); } } catch (Exception e) { if (entityRecord.getId() == null) { throw new ObjectCreateException(entity.getName(), e); } else { throw new ObjectUpdateException(entity.getName(), entityRecord.getId(), e); } } }
@Test public void shouldNotUpdateGridSizeWhenUsernameIsBlank() { EntityDto entityDto = new EntityDto(); entityDto.setReadOnlySecurityMode(null); entityDto.setSecurityMode(null); entityDto.setClassName(TestSample.class.getName()); EntityRecord entityRecord = new EntityRecord(ENTITY_ID + 1, null, new ArrayList<FieldRecord>()); when(entityService.getEntity(ENTITY_ID + 1)).thenReturn(entityDto); mockDataService(); instanceService.getEntityRecords(entityRecord.getId(), new QueryParams(1, 100)); verify(entityService).getEntityFieldsForUI(ENTITY_ID + 1); verify(userPreferencesService, never()).updateGridSize(anyLong(), anyString(), anyInt()); }
private HistoryRecord convertToHistoryRecord( Object object, EntityDto entity, Long instanceId, MotechDataService service) { Long entityId = entity.getId(); EntityRecord entityRecord = instanceToRecord(object, entity, entityService.getEntityFields(entityId), service); Long historyInstanceSchemaVersion = (Long) PropertyUtil.safeGetProperty( object, HistoryTrashClassHelper.schemaVersion(object.getClass())); Long currentSchemaVersion = entityService.getCurrentSchemaVersion(entity.getClassName()); return new HistoryRecord( entityRecord.getId(), instanceId, historyInstanceSchemaVersion.equals(currentSchemaVersion), entityRecord.getFields()); }
@Before public void setUpEntities() { book = new EntityDto("Book"); author = new EntityDto("Author"); authorFieldInBook = fieldDto("author", ManyToManyRelationship.class); authorFieldInBook.addMetadata(new MetadataDto(RELATED_CLASS, "Author")); FieldDto bookFieldInAuthor = fieldDto("book", ManyToManyRelationship.class); bookFieldInAuthor.addMetadata(new MetadataDto(RELATED_CLASS, "Book")); when(schemaHolder.getFields(book)).thenReturn(singletonList(authorFieldInBook)); when(schemaHolder.getFields(author)).thenReturn(singletonList(bookFieldInAuthor)); entity1 = new EntityDto("Entity1"); entity2 = new EntityDto("Entity2"); entity3 = new EntityDto("Entity3"); FieldDto entity1Field = fieldDto("entity1", OneToOneRelationship.class); entity1Field.addMetadata(new MetadataDto(RELATED_CLASS, "Entity2")); FieldDto entity2Field = fieldDto("entity2", OneToOneRelationship.class); entity2Field.addMetadata(new MetadataDto(RELATED_CLASS, "Entity3")); when(schemaHolder.getFields(entity1)).thenReturn(singletonList(entity1Field)); when(schemaHolder.getFields(entity2)).thenReturn(singletonList(entity2Field)); parentEntity = new EntityDto("Parent"); childEntity = new EntityDto("Child"); childEntity.setSuperClass("Parent"); binaryTree = new EntityDto("Binary tree"); FieldDto leftChild = fieldDto("leftChild", "Left child", OneToOneRelationship.class); leftChild.addMetadata(new MetadataDto(RELATED_CLASS, "Binary tree")); FieldDto rightChild = fieldDto("rightChild", "Right child", OneToOneRelationship.class); rightChild.addMetadata(new MetadataDto(RELATED_CLASS, "Binary tree")); when(schemaHolder.getFields(binaryTree)).thenReturn(asList(leftChild, rightChild)); entity1.setRecordHistory(true); entity2.setRecordHistory(true); entity3.setRecordHistory(true); book.setRecordHistory(true); author.setRecordHistory(true); parentEntity.setRecordHistory(true); childEntity.setRecordHistory(true); binaryTree.setRecordHistory(true); }
@Test public void shouldUpdateGridSize() { setUpSecurityContext(); EntityDto entityDto = new EntityDto(); entityDto.setReadOnlySecurityMode(null); entityDto.setSecurityMode(null); entityDto.setClassName(TestSample.class.getName()); EntityRecord entityRecord = new EntityRecord(ENTITY_ID + 1, null, new ArrayList<>()); when(entityService.getEntity(ENTITY_ID + 1)).thenReturn(entityDto); mockDataService(); instanceService.getEntityRecords(entityRecord.getId(), new QueryParams(1, 100)); verify(entityService).getEntityFieldsForUI(ENTITY_ID + 1); verify(userPreferencesService).updateGridSize(ENTITY_ID + 1, "motech", 100); }
private Class<?> getEntityClass(EntityDto entity) throws ClassNotFoundException { // get the declaring bundle, for DDE the module bundle, for EUDE the generated entities bundle Bundle declaringBundle; if (entity.isDDE()) { declaringBundle = MdsBundleHelper.searchForBundle(bundleContext, entity); } else { declaringBundle = WebBundleUtil.findBundleBySymbolicName( bundleContext, Constants.BundleNames.MDS_ENTITIES_SYMBOLIC_NAME); } Class<?> clazz; // if no bundle found, fallback to the MDSClassLoader if (declaringBundle == null) { clazz = MDSClassLoader.getInstance().loadClass(entity.getClassName()); } else { clazz = declaringBundle.loadClass(entity.getClassName()); } return clazz; }
private void processAnnotationScanningResults( List<EntityProcessorOutput> entityProcessorOutput, Map<String, List<LookupDto>> lookupProcessingResult) { Map<String, Long> entityIdMappings = new HashMap<>(); for (EntityProcessorOutput result : entityProcessorOutput) { EntityDto processedEntity = result.getEntityProcessingResult(); EntityDto entity = entityService.getEntityByClassName(processedEntity.getClassName()); if (entity == null) { entity = entityService.createEntity(processedEntity); } entityIdMappings.put(entity.getClassName(), entity.getId()); entityService.updateRestOptions(entity.getId(), result.getRestProcessingResult()); entityService.updateTracking(entity.getId(), result.getTrackingProcessingResult()); entityService.addFields(entity, result.getFieldProcessingResult()); entityService.addFilterableFields(entity, result.getUiFilterableProcessingResult()); entityService.addDisplayedFields(entity, result.getUiDisplayableProcessingResult()); entityService.updateSecurityOptions( entity.getId(), processedEntity.getSecurityMode(), processedEntity.getSecurityMembers()); entityService.updateMaxFetchDepth(entity.getId(), processedEntity.getMaxFetchDepth()); entityService.addNonEditableFields(entity, result.getNonEditableProcessingResult()); } for (Map.Entry<String, List<LookupDto>> entry : lookupProcessingResult.entrySet()) { entityService.addLookups(entityIdMappings.get(entry.getKey()), entry.getValue()); } }
private void validateNonEditableProperty(EntityDto entity) { if (entity.isNonEditable()) { throw new EntityInstancesNonEditableException(); } }
private MotechDataService getServiceForEntity(EntityDto entity) { String className = entity.getClassName(); return DataServiceHelper.getDataService(bundleContext, className); }
private void mockTestClassEntity() { EntityDto testClassEntity = mock(EntityDto.class); when(testClassEntity.getClassName()).thenReturn(TestClass.class.getName()); when(testClassEntity.getId()).thenReturn(TEST_CLASS_ID); mockEntity(TestClass.class, TEST_CLASS_ID, testClassEntity); }
@Before public void setUp() { when(entity.getClassName()).thenReturn(TestSample.class.getName()); when(entity.getId()).thenReturn(ENTITY_ID); when(bundleContext.getBundles()).thenReturn(new Bundle[0]); }
@Test public void shouldUpdateRelatedFields() { TestSample test1 = new TestSample("someString", 4); TestSample test2 = new TestSample("otherString", 5); TestSample test3 = new TestSample("sample", 6); RelationshipsUpdate oneToOneUpdate = new RelationshipsUpdate(); oneToOneUpdate.getAddedIds().add(6L); RelationshipsUpdate oneToManyUpdate = buildRelationshipUpdate(); List<FieldRecord> fieldRecords = asList( FieldTestHelper.fieldRecord("title", String.class.getName(), "String field", "Default"), FieldTestHelper.fieldRecord( TypeDto.ONE_TO_MANY_RELATIONSHIP, "testSamples", "Related field", oneToManyUpdate), FieldTestHelper.fieldRecord( TypeDto.ONE_TO_ONE_RELATIONSHIP, "testSample", "Other Related field", oneToOneUpdate)); EntityRecord entityRecord = new EntityRecord(null, ANOTHER_ENTITY_ID, fieldRecords); mockSampleFields(); mockDataService(); mockEntity(); EntityDto entityWithRelatedField = mock(EntityDto.class); when(entityService.getEntity(ANOTHER_ENTITY_ID)).thenReturn(entityWithRelatedField); when(entityWithRelatedField.getClassName()).thenReturn(AnotherSample.class.getName()); when(entityWithRelatedField.getId()).thenReturn(ENTITY_ID + 1); ServiceReference serviceReferenceForClassWithRelatedField = mock(ServiceReference.class); MotechDataService serviceForClassWithRelatedField = mock(MotechDataService.class); when(bundleContext.getServiceReference( ClassName.getInterfaceName(AnotherSample.class.getName()))) .thenReturn(serviceReferenceForClassWithRelatedField); when(bundleContext.getService(serviceReferenceForClassWithRelatedField)) .thenReturn(serviceForClassWithRelatedField); when(motechDataService.findById(4L)).thenReturn(test1); when(motechDataService.findById(5L)).thenReturn(test2); when(motechDataService.findById(6L)).thenReturn(test3); when(motechDataService.findByIds(oneToManyUpdate.getAddedIds())) .thenReturn(Arrays.asList(test1, test2)); when(entityService.getEntityFieldsForUI(ANOTHER_ENTITY_ID)) .thenReturn( asList( FieldTestHelper.fieldDto( 5L, "title", String.class.getName(), "String field", "Default"), FieldTestHelper.fieldDto( 6L, "testSamples", TypeDto.ONE_TO_MANY_RELATIONSHIP.getTypeClass(), "Related field", null))); ArgumentCaptor<AnotherSample> captor = ArgumentCaptor.forClass(AnotherSample.class); instanceService.saveInstance(entityRecord, null); verify(serviceForClassWithRelatedField).create(captor.capture()); AnotherSample capturedValue = captor.getValue(); assertEquals(capturedValue.getTestSample(), test3); assertEquals(capturedValue.getTestSamples().size(), 3); assertEquals(capturedValue.getTitle(), "Default"); assertTrue(capturedValue.getTestSamples().contains(test1)); assertFalse(capturedValue.getTestSamples().contains(test3)); assertTrue(capturedValue.getTestSamples().contains(test2)); }
private void mockEntity(Class<?> entityClass, long entityId, EntityDto entity) { when(entityService.getEntity(entityId)).thenReturn(entity); when(entityService.getEntityByClassName(entityClass.getName())).thenReturn(entity); when(entity.getClassName()).thenReturn(entityClass.getName()); when(entity.getId()).thenReturn(entityId); }
@Override public List<LookupDto> getAvailableLookups(String entityName) { EntityDto entity = getEntityByEntityClassName(entityName); AdvancedSettingsDto settingsDto = entityService.getAdvancedSettings(entity.getId(), true); return settingsDto.getIndexes(); }