/*
* Copyright (C) 2014 GG-Net GmbH - Oliver Günther
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.ggnet.dwoss.receipt;
import eu.ggnet.dwoss.spec.entity.piece.Cpu;
import eu.ggnet.dwoss.spec.entity.piece.Gpu;
import eu.ggnet.dwoss.spec.eao.ProductFamilyEao;
import eu.ggnet.dwoss.spec.entity.DesktopBundle;
import eu.ggnet.dwoss.spec.eao.GpuEao;
import eu.ggnet.dwoss.spec.entity.piece.Display;
import eu.ggnet.dwoss.spec.entity.ProductFamily;
import eu.ggnet.dwoss.spec.eao.DisplayEao;
import eu.ggnet.dwoss.spec.eao.CpuEao;
import eu.ggnet.dwoss.spec.eao.ProductSeriesEao;
import eu.ggnet.dwoss.spec.entity.DisplayAble;
import eu.ggnet.dwoss.spec.eao.ProductModelEao;
import eu.ggnet.dwoss.spec.entity.ProductSeries;
import eu.ggnet.dwoss.spec.entity.ProductModel;
import eu.ggnet.dwoss.spec.entity.Desktop;
import eu.ggnet.dwoss.spec.entity.ProductSpec;
import eu.ggnet.dwoss.spec.eao.ProductSpecEao;
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import eu.ggnet.dwoss.rules.ProductGroup;
import eu.ggnet.dwoss.rules.TradeName;
import eu.ggnet.dwoss.spec.assist.SpecPu;
import eu.ggnet.dwoss.spec.assist.Specs;
import eu.ggnet.dwoss.spec.emo.DisplayEmo;
import eu.ggnet.dwoss.spec.emo.ProductModelEmo;
import eu.ggnet.dwoss.spec.format.SpecFormater;
import eu.ggnet.dwoss.uniqueunit.assist.UniqueUnits;
import eu.ggnet.dwoss.uniqueunit.eao.ProductEao;
import eu.ggnet.dwoss.uniqueunit.entity.Product;
/**
* This Logic is used in Reciept to handle all modifications to ProductSpec,Product and SopoProduct.
*
* @author oliver.guenther
*/
@Stateless
public class ProductProcessorOperation implements ProductProcessor {
private final static Logger L = LoggerFactory.getLogger(ProductProcessorOperation.class);
@Inject
@Specs
private EntityManager specEm;
@Inject
@UniqueUnits
private EntityManager uuEm;
/**
* Creates a new Cpu instance.
*
* @param cpu the Cpu to create
* @return the Cpu instance from databes, but detached.
* @throws IllegalArgumentException if there exist a cpu with the same series and the name.
*/
@Override
public Cpu create(Cpu cpu) throws IllegalArgumentException {
EntityManager em = specEm;
CpuEao cpuEao = new CpuEao(specEm);
Cpu existendCpu = cpuEao.find(cpu.getSeries(), cpu.getModel());
if ( existendCpu != null ) throw new IllegalArgumentException("Cpu with same Series and Name exists " + existendCpu);
em.persist(cpu);
return cpu;
}
/**
* Updates an existing detached Cpu.
*
* @param cpu the detached Cpu
* @return the reatached updated Cpu
* @throws IllegalArgumentException if there allready exists a Cpu with the same series and name
*/
@Override
public Cpu update(Cpu cpu) throws IllegalArgumentException {
EntityManager em = specEm;
CpuEao cpuEao = new CpuEao(em);
Cpu existendCpu = cpuEao.find(cpu.getSeries(), cpu.getModel());
if ( existendCpu != null && existendCpu.getId() != cpu.getId() )
throw new IllegalArgumentException("Cpu with same Series and Name exists " + existendCpu);
return em.merge(cpu);
}
/**
* Creates a new Gpu instance.
*
* @param gpu the Gpu to create
* @return the Gpu instance from databes, but detached.
* @throws IllegalArgumentException if there exist a Gpu with the same series and the name.
*/
@Override
public Gpu create(Gpu gpu) throws IllegalArgumentException {
EntityManager em = specEm;
GpuEao gpuEao = new GpuEao(em);
Gpu existendGpu = gpuEao.find(gpu.getSeries(), gpu.getModel());
if ( existendGpu != null ) throw new IllegalArgumentException("Gpu with same Series and Name exists " + existendGpu);
em.persist(gpu);
return gpu;
}
/**
* Updates an existing detached Gpu.
*
* @param gpu the detached Gpu
* @return the reatached updated Gpu
* @throws IllegalArgumentException if there allready exists a Gpu with the same series and name
*/
@Override
public Gpu update(Gpu gpu) throws IllegalArgumentException {
EntityManager em = specEm;
GpuEao gpuEao = new GpuEao(em);
Gpu existendGpu = gpuEao.find(gpu.getSeries(), gpu.getModel());
if ( existendGpu != null && existendGpu.getId() != gpu.getId() )
throw new IllegalArgumentException("Gpu with same Series and Name exists " + existendGpu);
return em.merge(gpu);
}
/**
* Creates a new ProductModel and Persists it.
* Multistep Process:
* <ol>
* <li>Validate and throw exception if a model with the same name exists</li>
* <li>Selection of Family and Series
* <ul>
* <li>If Family is null and Series is null → find or create default Series and default Family</li>
* <li>If only Family is null → find or create default default Family for Series</li>
* <li>Else use supplied Family</li>
* </ul>
* </li>
* <li>Persist new Model with Family</li>
* </ol>
*
* @param brand must not be null
* @param group must not be null
* @param series if null, default is used
* @param family if null, default is used
* @param modelName the name of the model
*
* @return the persisted and detached Model
*/
@Override
public ProductModel create(final TradeName brand, final ProductGroup group, ProductSeries series, ProductFamily family, final String modelName) {
EntityManager em = specEm;
// 1. check if there exits a model anytwhere with the same name. -> throw Exception
ProductModelEao modelEao = new ProductModelEao(em);
ProductModel model = modelEao.find(modelName);
if ( model != null ) throw new RuntimeException("There exits a model " + model + " but we want to create it");
// 2. Select Family and Series
if ( family != null && family.getId() != 0 ) {
ProductFamilyEao familyEao = new ProductFamilyEao(em);
family = familyEao.findById(family.getId());
} else {
if ( series != null && series.getId() != 0 ) {
ProductSeriesEao seriesEao = new ProductSeriesEao(em);
series = seriesEao.findById(series.getId());
} else {
ProductSeriesEao seriesEao = new ProductSeriesEao(em);
series = seriesEao.find(brand, group, SpecPu.DEFAULT_NAME);
if ( series == null ) {
series = new ProductSeries(brand, group, SpecPu.DEFAULT_NAME);
em.persist(series);
}
}
for (ProductFamily f : series.getFamilys()) {
if ( f.getName().equals(SpecPu.DEFAULT_NAME) ) {
family = f;
}
}
if ( family == null ) {
family = new ProductFamily(SpecPu.DEFAULT_NAME);
family.setSeries(series);
em.persist(family);
}
}
// 3. Create Model
model = new ProductModel(modelName);
model.setFamily(family);
em.persist(model);
return model;
}
/**
* Creates and Persists a ProducFamily.
* <ol>
* <li>Validate and throw exception if a family with the same name exists</li>
* <li>Selection of Series
* <ul>
* <li>If Series is null → find or create default Series</li>
* <li>Else use supplied Series</li>
* </ul>
* </li>
* <li>Persist new Family with Series</li>
* </ol>
*
* @param brand the brand
* @param group the group
* @param series the series
* @param familyName the familyName
*
* @return the persisted and detached ProductFamily
*/
@Override
public ProductFamily create(final TradeName brand, final ProductGroup group, ProductSeries series, final String familyName) {
EntityManager em = specEm;
// 1. check if there exits a model anytwhere with the same name. -> throw Exception
ProductFamilyEao familyEao = new ProductFamilyEao(em);
ProductFamily family = familyEao.find(familyName);
if ( family != null ) throw new RuntimeException("There exits a family " + family + " but we want to create it");
// 2. Create Family
family = new ProductFamily(familyName);
if ( series != null && series.getId() != 0 ) {
// 3. if series not null, get from db
ProductSeriesEao seriesEao = new ProductSeriesEao(em);
series = seriesEao.findById(series.getId());
} else {
// 4. get or create default series
ProductSeriesEao seriesEao = new ProductSeriesEao(em);
series = seriesEao.find(brand, group, SpecPu.DEFAULT_NAME);
if ( series == null ) {
series = new ProductSeries(brand, group, SpecPu.DEFAULT_NAME);
em.persist(series);
}
}
family.setSeries(series);
em.persist(family);
return family;
}
/**
* Creates a new ProductSpec and the relating Product and SopoProduct.
*
* The process has multiple steps:
* <ol>
* <li>Merge the ProductModel and set it in the Spec</li>
* <li>If Spec is a DisplayAble its assumed the Display is either existent or new.<br />
* In case it exists, the existent value will be set in the Spec</li>
* <li>If Spec is a Desktop its assumed that the Cpu and Gpu are existent, and they are merged and set.</li>
* <li>The Spec is persisted</li>
* <li>A Product is created and persisted</li>
* <li>The Spec.productId is set to Product.id (WeakReference)</li>
* <li>A SopoProduct is searched. If found, it is updated, else a new one is created</li>
* </ol>
*
* @param spec the spec to persist, must not be null
* @param model the model for the spec, must not be null or new
* @throws IllegalArgumentException if Cpu or Gpu in a Desktop are new.
*
* @return the detached created ProductSpec
*/
// TODO: Check if the model as parameter is still needed.
@Override
public ProductSpec create(ProductSpec spec, ProductModel model) throws IllegalArgumentException {
if ( model == null ) throw new NullPointerException("Model is null");
if ( spec == null ) throw new NullPointerException("ProductSpec is null");
// Hint: Normally the column unique option should do that, but HSQLDB somehow lost it.
if ( new ProductEao(uuEm).findByPartNo(spec.getPartNo()) != null )
throw new IllegalArgumentException("PartNo=" + spec.getPartNo() + " exists allready, but create is calles");
ProductModelEmo productModelEmo = new ProductModelEmo(specEm);
model = productModelEmo.request(
model.getFamily().getSeries().getBrand(),
model.getFamily().getSeries().getGroup(),
model.getFamily().getSeries().getName(),
model.getFamily().getName(),
model.getName());
spec.setModel(model);
if ( spec instanceof DisplayAble ) {
DisplayAble da = (DisplayAble)spec;
da.setDisplay(new DisplayEmo(specEm).weakRequest(
da.getDisplay().getSize(),
da.getDisplay().getResolution(),
da.getDisplay().getType(),
da.getDisplay().getRation()));
}
if ( spec instanceof Desktop ) {
Desktop desktop = (Desktop)spec;
if ( desktop.getCpu() == null || desktop.getGpu() == null ) throw new IllegalArgumentException("Cpu or Gpu of a Desktop are null. " + desktop);
Cpu cpu = new CpuEao(specEm).findById(desktop.getCpu().getId());
Gpu gpu = new GpuEao(specEm).findById(desktop.getGpu().getId());
if ( cpu != null ) desktop.setCpu(cpu);
if ( gpu != null ) desktop.setGpu(gpu);
}
if ( spec instanceof DesktopBundle ) {
DesktopBundle bundle = (DesktopBundle)spec;
if ( bundle.getDesktop().getId() == 0 || bundle.getMonitor().getId() == 0 )
throw new IllegalArgumentException("Monitor or Desktop are new. Impossible");
ProductSpecEao specEao = new ProductSpecEao(specEm);
bundle.setDesktop(specEao.findById(bundle.getDesktop().getId()));
bundle.setMonitor(specEao.findById(bundle.getMonitor().getId()));
}
L.info("Persisting {} including model change={}", SpecFormater.toDetailedName(spec), (model == spec.getModel()));
specEm.persist(spec);
EntityManager uniqueUnitEm = uuEm;
ProductEao productEao = new ProductEao(uniqueUnitEm);
Product product = productEao.findByPartNo(spec.getPartNo());
if ( product == null ) product = new Product();
product.setGroup(spec.getModel().getFamily().getSeries().getGroup());
product.setTradeName(spec.getModel().getFamily().getSeries().getBrand());
product.setPartNo(spec.getPartNo());
product.setName(spec.getModel().getName());
product.setDescription(SpecFormater.toSingleLine(spec));
L.debug("persisting {}", product);
if ( !uniqueUnitEm.contains(product) ) uniqueUnitEm.persist(product);
L.debug("creating weak reference ProductSpec.productId=Product.id value ({})", product.getId());
spec.setProductId(product.getId());
return spec;
}
/**
* Return a refreshed ProductSpec with the selected model added.
*
* @param spec the spec to be refreshed.
* @param model the model to be assosiated, must not be null, but may be equal to spec.getModel
* @return
* @throws IllegalArgumentException
*/
@Override
public ProductSpec refresh(ProductSpec spec, ProductModel model) throws IllegalArgumentException {
if ( spec.getProductId() == null ) throw new IllegalArgumentException("ProductSpec has no productId, violation ! " + spec);
if ( spec.getModel().equals(model) ) return spec;
// 1. Validation
L.debug("refreshing {}", spec);
spec = new ProductSpecEao(specEm).findById(spec.getId());
spec.setModel(new ProductModelEao(specEm).findById(model.getId()));
return spec;
}
/**
* Updates an existing ProductSpec and the relating Product and SopoProduct.
*
* The process has multiple steps:
* <ol>
* <li>Validate and throw IllegalArgumentException:
* <ul>
* <li>if the ProductSpec.productId == null</li>
* <li>if there does not exist a Product with ProductSpec.productId</li>
* <li>if there does not exist a SopoProduct with Product.partNo (unchanged)</li>
* </ul>
* </li>
* <li>If Spec is a DisplayAble its assumed the Display is either existent or new.<br />
* In case it exists, the existent value will be set in the Spec</li>
* <li>if the supplied ProductModel is different from ProductSpec.getModel it is merged and set</li>
* <li>Overwrite all changes in Product</li>
* <li>Overwrite all changes in SopoProduct</li>
* <li> If PartNo change propagate to all matching SopoUnits</li>
* </ol>
*
* @param spec the spec to be updated, must not be null and not new
* @throws IllegalArgumentException if spec.productId == null
* @return the updated and detached instance of ProductSpec
*/
@Override
public ProductSpec update(ProductSpec spec) throws IllegalArgumentException {
// 1. Validation
if ( spec.getProductId() == null ) throw new IllegalArgumentException("ProductSpec has no productId, violation ! " + spec);
ProductEao productEao = new ProductEao(uuEm);
Product product = productEao.findById(spec.getProductId());
if ( product == null ) throw new IllegalArgumentException("ProductSpec.productId=" + spec.getProductId() + " does not have a Product");
// 2. + 3. Update Spec
if ( spec instanceof DisplayAble && ((DisplayAble)spec).getDisplay().getId() == 0 ) {
DisplayAble monitor = (DisplayAble)spec;
DisplayEao displayEao = new DisplayEao(specEm);
Display display = monitor.getDisplay();
display = displayEao.find(display.getSize(), display.getResolution(), display.getType(), display.getRation());
if ( display != null ) monitor.setDisplay(display);
}
L.info("updateing {}", SpecFormater.toDetailedName(spec));
spec = specEm.merge(spec);
// 4. overwrite Product
product.setGroup(spec.getModel().getFamily().getSeries().getGroup());
product.setTradeName(spec.getModel().getFamily().getSeries().getBrand());
product.setPartNo(spec.getPartNo());
product.setName(spec.getModel().getName());
product.setDescription(SpecFormater.toSingleLine(spec));
L.debug("updateing {}", product);
return spec;
}
}