// $HeadURL:
// http://seanderickson1@forge.abcd.harvard.edu/svn/screensaver/branches/serickson/2920-rev2/core/src/main/java/edu/harvard/med/screensaver/ui/libraries/LibraryCopyDetail.java
// $
// $Id$
//
// Copyright © 2006, 2010, 2011, 2012 by the President and Fellows of Harvard College.
//
// Screensaver is an open-source project developed by the ICCB-L and NSRB labs
// at Harvard Medical School. This software is distributed under the terms of
// the GNU General Public License.
package edu.harvard.med.screensaver.ui.libraries;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Arrays;
import java.util.List;
import javax.faces.model.SelectItem;
import org.apache.log4j.Logger;
import org.hibernate.exception.ConstraintViolationException;
import org.springframework.orm.jpa.JpaSystemException;
import org.springframework.transaction.annotation.Transactional;
import com.google.common.collect.ImmutableSet;
import edu.harvard.med.screensaver.ScreensaverConstants;
import edu.harvard.med.screensaver.db.GenericEntityDAO;
import edu.harvard.med.screensaver.db.LibrariesDAO;
import edu.harvard.med.screensaver.model.BusinessRuleViolationException;
import edu.harvard.med.screensaver.model.MolarConcentration;
import edu.harvard.med.screensaver.model.MolarUnit;
import edu.harvard.med.screensaver.model.libraries.Copy;
import edu.harvard.med.screensaver.model.libraries.CopyUsageType;
import edu.harvard.med.screensaver.model.libraries.Library;
import edu.harvard.med.screensaver.model.libraries.Plate;
import edu.harvard.med.screensaver.model.users.AdministratorUser;
import edu.harvard.med.screensaver.model.users.ScreensaverUser;
import edu.harvard.med.screensaver.model.users.ScreensaverUserRole;
import edu.harvard.med.screensaver.service.libraries.PlateUpdater;
import edu.harvard.med.screensaver.ui.arch.util.JSFUtils;
import edu.harvard.med.screensaver.ui.arch.util.UISelectOneBean;
import edu.harvard.med.screensaver.ui.arch.view.EditResult;
import edu.harvard.med.screensaver.ui.arch.view.EditableEntityViewerBackingBean;
import edu.harvard.med.screensaver.ui.arch.view.aspects.UICommand;
import edu.harvard.med.screensaver.util.NullSafeUtils;
import edu.harvard.med.screensaver.util.StringUtils;
/**
*/
public class LibraryCopyDetail extends EditableEntityViewerBackingBean<Copy>
{
private static Logger log = Logger.getLogger(LibraryCopyDetail.class);
private static final MolarUnit DEFAULT_PLATE_MOLAR_CONCENTRATION_UNITS
= MolarUnit.MILLIMOLAR;
private LibraryCopyViewer _libraryCopyViewer;
private LibraryViewer _libraryViewer;
private PlateUpdater _plateUpdater;
private LibrariesDAO _librariesDao;
private UISelectOneBean<MolarUnit> _molarConcentrationType;
private String _molarConcentrationValue;
private BigDecimal _mgMlConcentration;
private BigDecimal _dilutionFactor;
/**
* @motivation for CGLIB2
*/
protected LibraryCopyDetail()
{}
public LibraryCopyDetail(LibraryCopyDetail libraryCopyDetailProxy,
GenericEntityDAO dao,
LibrariesDAO librariesDao,
LibraryCopyViewer libraryCopyViewer,
LibraryViewer libraryViewer,
PlateUpdater plateUpdater)
{
super(libraryCopyDetailProxy,
Copy.class,
EDIT_LIBRARY_COPY,
dao);
_librariesDao = librariesDao;
_libraryCopyViewer = libraryCopyViewer;
_libraryViewer = libraryViewer;
_plateUpdater = plateUpdater;
_molarConcentrationValue = null;
_molarConcentrationType = null;
_mgMlConcentration = null;
_dilutionFactor = null;
}
@Override
protected void initializeViewer(Copy entity)
{}
@Override
protected void initializeEntity(Copy copy)
{
getDao().needReadOnly(copy, Copy.library);
_librariesDao.calculateCopyVolumeStatistics(ImmutableSet.of(copy));
_molarConcentrationValue = null;
_molarConcentrationType = null;
_mgMlConcentration = null;
_dilutionFactor = null;
}
@Override
protected boolean validateEntity(Copy entity)
{
boolean valid = true;
if (getWellConcentrationDilutionFactor() != null
&& !StringUtils.isEmpty(getMolarConcentrationValue()) ||
getWellConcentrationDilutionFactor() != null
&& getMgMlConcentration() != null ||
!StringUtils.isEmpty(getMolarConcentrationValue())
&& getMgMlConcentration() != null) {
showMessage("libraries.enterOnlyOneConcentrationValue");
valid = false;
}
if (!StringUtils.isEmpty(getMolarConcentrationValue())) {
MolarConcentration newConcentration = null;
try {
newConcentration =
MolarConcentration.makeConcentration(
getMolarConcentrationValue(),
getMolarConcentrationType().getSelection());
}
catch (Exception e) {
showMessage("invalidUserInput", "Concentration (molar)", e.getLocalizedMessage());
return false;
}
if(entity.getPrimaryWellMolarConcentration() == null )
{
showMessage("invalidUserInput", "Molar Concentration",
"Cannot set the dilution factor using an absolute concentration if "
+ "the library well concentrations for the copy plates have not been set. "
+ "Set using the dilution factor instead");
// TODO: [#2920] make an error message property for this
return false;
}
if(!!! NullSafeUtils.nullSafeEquals(
entity.getMaxMolarConcentration(), entity.getMinMolarConcentration()) ||
!!! NullSafeUtils.nullSafeEquals(
entity.getMaxMolarConcentration(), entity.getPrimaryWellMolarConcentration()) )
{
showMessage("invalidUserInput", "Molar Concentration",
"Cannot set the plate dilution factor using an absolute concentration "
+ "if the wells of the plate have varying concentrations. "
+ "Set using the plate dilution factor instead");
// TODO: [#2920] make an error message property for this
valid = false;
}
if(entity.getPrimaryWellMolarConcentration().compareTo(
newConcentration) < 0 ) {
showMessage("invalidUserInput", "molar Concentration",
"Target concentration cannot be more than the undiluted "
+ "primary well concentration ("
+ entity.getPrimaryWellMolarConcentration()
+ ") (only dilution is allowed).");
// TODO: [#2920] make an error message property for this
valid = false;
}
if(!valid) return false;
// 2. calculate a dilution factor
BigDecimal newDilutionFactor =
entity.getPrimaryWellMolarConcentration().getValue().divide(
newConcentration.getValue(), RoundingMode.HALF_UP);
newDilutionFactor =
newDilutionFactor.scaleByPowerOfTen(
newConcentration.getUnits().getScale()
- entity.getPrimaryWellMolarConcentration().getUnits().getScale());
newDilutionFactor = newDilutionFactor.setScale(
ScreensaverConstants.PLATE_DILUTION_FACTOR_SCALE, RoundingMode.HALF_UP);
//TODO: rename "copy dilution factor" or "dilution factor"
_dilutionFactor = newDilutionFactor;
}
if (getMgMlConcentration() != null) {
if(entity.getPrimaryWellMgMlConcentration() == null )
{
showMessage("invalidUserInput", "mg/mL Concentration",
"Cannot set the plate dilution factor using an absolute "
+ "concentration if the library well concentrations for the "
+ "plate have not been set. "
+ "Set using the plate dilution factor instead");
// TODO: [#2920] make an error message property for this
return false;
}
if(!!! NullSafeUtils.nullSafeEquals(
entity.getMaxMgMlConcentration(), entity.getMinMgMlConcentration()) ||
!!! NullSafeUtils.nullSafeEquals(
entity.getMaxMgMlConcentration(), entity.getPrimaryWellMgMlConcentration()) )
{
showMessage("invalidUserInput", "mg/mL Concentration",
"Cannot set the plate dilution factor using an absolute "
+ "concentration if the wells of the plate have varying concentrations. "
+ "Set using the plate dilution factor instead");
// TODO: [#2920] make an error message property for this
return false;
}
if(entity.getPrimaryWellMgMlConcentration().compareTo(getMgMlConcentration()) < 0 ) {
showMessage("invalidUserInput", "mg/mL Concentration",
"Target concentration cannot be more than the undiluted primary "
+ "well concentration (" + entity.getPrimaryWellMgMlConcentration()
+ ") (only dilution is allowed).");
// TODO: [#2920] make an error message property for this
valid = false;
}
BigDecimal newDilutionFactor =
entity.getPrimaryWellMgMlConcentration().divide(
getMgMlConcentration(),
ScreensaverConstants.PLATE_DILUTION_FACTOR_SCALE,
RoundingMode.HALF_UP);
// TODO: An error occurred during the requested operation:
// Non-terminating decimal expansion; no exact representable decimal result.
_dilutionFactor = newDilutionFactor;
}
if (_dilutionFactor != null
&& _dilutionFactor.compareTo(new BigDecimal("1.0")) < 0 )
{
showMessage("invalidUserInput", "dilution factor",
"The dilution factor must be greater than 1");
return false;
}
if(!valid) return false;
return super.validateEntity(entity);
}
@Override
protected void updateEntityProperties(Copy entity)
{
super.updateEntityProperties(entity);
ScreensaverUser screensaverUser = getCurrentScreensaverUser().getScreensaverUser();
if (! (screensaverUser instanceof AdministratorUser) ||
!((AdministratorUser)screensaverUser).isUserInRole(
ScreensaverUserRole.LIBRARY_COPIES_ADMIN)) {
throw new BusinessRuleViolationException(
"only library copies administrators can edit library copy plates");
}
AdministratorUser adminUser = getDao().reloadEntity((AdministratorUser) getScreensaverUser());
if( getWellConcentrationDilutionFactor() != null)
{
if (!!!NullSafeUtils.nullSafeEquals(
getWellConcentrationDilutionFactor(),
entity.getWellConcentrationDilutionFactor())) {
StringBuilder updateComments =
new StringBuilder().append("Dilution factor changed from '")
.append(NullSafeUtils.toString(
entity.getWellConcentrationDilutionFactor(),
"<not specified>"))
.append("' to '")
.append(getWellConcentrationDilutionFactor()).append("'");
entity.createUpdateActivity(adminUser, updateComments.toString());
entity.setWellConcentrationDilutionFactor(getWellConcentrationDilutionFactor());
}
}
if(entity.getConcentrationStatistics() == null) {
// if the concentration hasn't been set, then it may be a new entity
// TODO: is there a better way to figure out if this is a new entity?
_plateUpdater.updatePrimaryPlateConcentrations(entity);
}
}
public String getMolarConcentrationValue()
{
return _molarConcentrationValue;
}
public void setMolarConcentrationValue(String value)
{
_molarConcentrationValue = value;
}
public UISelectOneBean<MolarUnit> getMolarConcentrationType()
{
try {
if (_molarConcentrationType == null) {
MolarConcentration c = null;
MolarUnit unit = (c == null ?
DEFAULT_PLATE_MOLAR_CONCENTRATION_UNITS
: c.getUnits()); // Todo: can we set default SM = mM, RNA = uM
_molarConcentrationType = new UISelectOneBean<MolarUnit>(MolarUnit.DISPLAY_VALUES, unit)
{
@Override
protected String makeLabel(MolarUnit t)
{
return t.getValue();
}
};
}
return _molarConcentrationType;
}
catch (Exception e) {
log.error("err: " + e);
return null;
}
}
public BigDecimal getMgMlConcentration()
{
return _mgMlConcentration;
}
public void setMgMlConcentration(BigDecimal mgMlConcentration)
{
_mgMlConcentration = mgMlConcentration;
}
public void setWellConcentrationDilutionFactor(BigDecimal value)
{
_dilutionFactor = value;
}
public BigDecimal getWellConcentrationDilutionFactor()
{
return _dilutionFactor;
}
@UICommand
@Override
public String delete()
{
String copyName = getEntity().getName();
try {
Library library = getEntity().getLibrary();
getDao().deleteEntity(getEntity());
showMessage("deletedEntity", "copy " + copyName);
_libraryViewer.getContextualSearchResults().reload();
return _libraryViewer.viewEntity(library);
}
catch (JpaSystemException e) {
if (e.contains(ConstraintViolationException.class)) {
showMessage("cannotDeleteEntityInUse", "Copy " + copyName);
return REDISPLAY_PAGE_ACTION_RESULT;
}
else {
throw e;
}
}
}
@Override
protected String postEditAction(EditResult editResult)
{
switch (editResult) {
case CANCEL_EDIT:
case SAVE_EDIT:
return _libraryCopyViewer.reload();
case CANCEL_NEW:
return _libraryViewer.reload();
case SAVE_NEW:
return _libraryViewer.viewEntity(getDao().reloadEntity(getEntity(),
true, Copy.library).getLibrary());
default:
return null;
}
}
public List<SelectItem> getCopyUsageTypeSelectItems()
{
List<CopyUsageType> values = Arrays.asList(CopyUsageType.values());
if (getEntity().getUsageType() == null) {
return JSFUtils.createUISelectItemsWithEmptySelection(
values, REQUIRED_VOCAB_FIELD_PROMPT);
}
return JSFUtils.createUISelectItems(values);
}
}