Java tutorial
/* * Copyright 2011-2016 CAST, Inc. * * This file is part of the CAST Wicket Modules: * see <http://code.google.com/p/cast-wicket-modules>. * * The CAST Wicket Modules are free software: you can redistribute and/or * modify them under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * The CAST Wicket Modules are distributed in the hope that they will be * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this software. If not, see <http://www.gnu.org/licenses/>. */ package org.cast.cwm.service; import java.util.Date; import java.util.Iterator; import java.util.List; import lombok.Getter; import lombok.Setter; import net.databinder.hib.Databinder; import net.databinder.models.hib.HibernateObjectModel; import net.databinder.models.hib.SortableHibernateProvider; import org.apache.wicket.Application; import org.apache.wicket.WicketRuntimeException; import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder; import org.apache.wicket.extensions.markup.html.repeater.data.table.ISortableDataProvider; import org.apache.wicket.markup.html.form.upload.FileUpload; import org.apache.wicket.model.IModel; import org.cast.cwm.data.BinaryFileData; import org.cast.cwm.data.IResponseType; import org.cast.cwm.data.Period; import org.cast.cwm.data.Prompt; import org.cast.cwm.data.Response; import org.cast.cwm.data.ResponseData; import org.cast.cwm.data.User; import org.cast.cwm.data.builders.ResponseCriteriaBuilder; import org.cast.cwm.data.models.PromptModel; import org.cast.cwm.data.models.ResponseListModel; import org.cast.cwm.data.models.ResponseModel; import org.hibernate.Criteria; import org.hibernate.LockOptions; import org.hibernate.Session.LockRequest; import org.hibernate.criterion.Projections; import org.hibernate.criterion.Restrictions; import com.google.inject.Inject; //import org.apache.wicket.extensions.markup.html.repeater.data.sort.ISortState; //import org.apache.wicket.extensions.markup.html.repeater.data.table.ISortableDataProvider; /** * A Hibernate implementation of the service class used to save/load/modify * {@link Response} objects. Eventually, this should be split into Abstract * and HibernateImpl classes. * * @author jbrookover * */ public class ResponseService implements IResponseService { @Inject protected ICwmService cwmService; @Inject private IEventService eventService; protected static ResponseService instance; @Getter @Setter protected Class<? extends Response> responseClass = Response.class; protected ResponseService() { /* Protected Constructor - use injection */} public static ResponseService get() { return instance; } /** * Use this Service class. Called in {@link Application#init()}. */ public static void useAsServiceInstance() { ResponseService.instance = new ResponseService(); } /** Create a new Response object of the application's preferred class */ protected Response newResponse() { try { return responseClass.newInstance(); } catch (Exception e) { throw new WicketRuntimeException("Could not instantiate response class", e); } } /* (non-Javadoc) * @see org.cast.cwm.service.IResponseService#newResponse(org.apache.wicket.model.IModel, org.cast.cwm.data.IResponseType, org.apache.wicket.model.IModel) */ @Override public IModel<Response> newResponse(IModel<User> user, IResponseType type, IModel<? extends Prompt> prompt) { Response instance = newResponse(); instance.setUser(user.getObject()); instance.setType(type); instance.setPrompt(prompt.getObject()); return new ResponseModel(instance); } /* (non-Javadoc) * @see org.cast.cwm.service.IResponseService#getResponsesForPrompt(org.apache.wicket.model.IModel) */ @Override @Deprecated public IModel<List<Response>> getResponsesForPrompt(IModel<? extends Prompt> p) { return getResponsesForPrompt(p, null); } /* (non-Javadoc) * @see org.cast.cwm.service.IResponseService#getResponseForPrompt(org.apache.wicket.model.IModel, org.apache.wicket.model.IModel) */ @Override public IModel<Response> getResponseForPrompt(IModel<? extends Prompt> p, IModel<User> u) { ResponseCriteriaBuilder c = new ResponseCriteriaBuilder(); c.setPromptModel(p); c.setUserModel(u); return new ResponseModel(c); } /* (non-Javadoc) * @see org.cast.cwm.service.IResponseService#getResponsesForPrompt(org.apache.wicket.model.IModel, org.apache.wicket.model.IModel) */ @Override @Deprecated public IModel<List<Response>> getResponsesForPrompt(IModel<? extends Prompt> p, IModel<User> u) { ResponseCriteriaBuilder c = new ResponseCriteriaBuilder(); c.setPromptModel(p); c.setUserModel(u); return new ResponseListModel(c); } /* (non-Javadoc) * @see org.cast.cwm.service.IResponseService#getResponsesForPrompt(org.apache.wicket.model.IModel, java.util.Date, java.util.Date) */ @Override public IModel<List<Response>> getResponsesForPrompt(IModel<? extends Prompt> p, Date from, Date to) { ResponseCriteriaBuilder c = new ResponseCriteriaBuilder(); c.setPromptModel(p); c.setFromDate(from); c.setToDate(to); return new ResponseListModel(c); } /* (non-Javadoc) * @see org.cast.cwm.service.IResponseService#getResponsesForPeriod(org.apache.wicket.model.IModel, org.apache.wicket.model.IModel) */ @Override public IModel<List<Response>> getResponsesForPeriod(IModel<? extends Prompt> p, IModel<Period> period) { ResponseCriteriaBuilder c = new ResponseCriteriaBuilder(); c.setPromptModel(p); c.setPeriodModel(period); return new ResponseListModel(c); } /* (non-Javadoc) * @see org.cast.cwm.service.IResponseService#getResponseProviderForPrompt(org.apache.wicket.model.IModel) */ @Override public ISortableDataProvider<Response, String> getResponseProviderForPrompt(IModel<? extends Prompt> p) { return getResponseProviderForPrompt(p, null); } /* (non-Javadoc) * @see org.cast.cwm.service.IResponseService#getResponseProviderForPrompt(org.apache.wicket.model.IModel, org.apache.wicket.model.IModel) */ @Override public ISortableDataProvider<Response, String> getResponseProviderForPrompt(IModel<? extends Prompt> p, IModel<User> u) { ResponseCriteriaBuilder c = new ResponseCriteriaBuilder(); c.setPromptModel(p); c.setUserModel(u); return new SortableHibernateProvider<Response>(Response.class, c); } @Override public ISortableDataProvider<Response, String> getResponseProviderForPromptAndPeriod(IModel<? extends Prompt> p, IModel<Period> mPeriod) { ResponseCriteriaBuilder c = new ResponseCriteriaBuilder(); c.setPromptModel(p); c.setPeriodModel(mPeriod); return new SortableHibernateProvider<Response>(Response.class, c); } /* (non-Javadoc) * @see org.cast.cwm.service.IResponseService#getResponseCountForPrompt(org.apache.wicket.model.IModel, org.cast.cwm.data.IResponseType, org.apache.wicket.model.IModel) */ @Override public Long getResponseCountForPrompt(IModel<? extends Prompt> mPrompt, IResponseType type, IModel<? extends User> mUser) { Criteria c = Databinder.getHibernateSession().createCriteria(Response.class); c.add(Restrictions.eq("prompt", mPrompt.getObject())); if (type != null) c.add(Restrictions.eq("type", type)); if (mUser != null && mUser.getObject() != null) c.add(Restrictions.eq("user", mUser.getObject())); c.add(Restrictions.eq("valid", true)); c.setProjection(Projections.rowCount()); c.setCacheable(true); return (Long) c.uniqueResult(); } /* (non-Javadoc) * @see org.cast.cwm.service.IResponseService#getLatestResponseByType(org.apache.wicket.model.IModel, org.cast.cwm.data.IResponseType) */ @Override public IModel<Response> getLatestResponseByType(IModel<? extends Prompt> p, IResponseType type) { ResponseCriteriaBuilder c = new ResponseCriteriaBuilder(); c.setPromptModel(p); c.setResponseType(type); c.setMaxResults(1); return new ResponseModel(c); } /* (non-Javadoc) * @see org.cast.cwm.service.IResponseService#getLatestResponseByTypeForUser(org.apache.wicket.model.IModel, org.apache.wicket.model.IModel, org.cast.cwm.data.IResponseType) */ @Override public IModel<Response> getLatestResponseByTypeForUser(IModel<? extends Prompt> p, IModel<User> u, IResponseType type) { ResponseCriteriaBuilder c = new ResponseCriteriaBuilder(); c.setPromptModel(p); c.setResponseType(type); c.setUserModel(u); c.setMaxResults(1); return new ResponseModel(c); } /* (non-Javadoc) * @see org.cast.cwm.service.IResponseService#saveTextResponse(org.apache.wicket.model.IModel, java.lang.String, java.lang.String) */ @Override public void saveTextResponse(IModel<Response> response, String message, String pageName) { genericSaveResponse(response, message, null, null, null, null, pageName); } /* (non-Javadoc) * @see org.cast.cwm.service.IResponseService#saveStarRating(org.apache.wicket.model.IModel, int) */ @Override public void saveStarRating(IModel<Response> mResponse, int score) { genericSaveResponse(mResponse, null, score, null, score, null, null); } /* (non-Javadoc) * @see org.cast.cwm.service.IResponseService#saveBinaryResponse(org.apache.wicket.model.IModel, byte[], java.lang.String, java.lang.String, java.lang.String) */ @Override public void saveBinaryResponse(IModel<Response> r, byte[] bytes, String mimeType, String fileName, String pageName) { BinaryFileData bd = new BinaryFileData(fileName, mimeType, bytes); genericSaveResponse(r, null, null, null, null, bd, pageName); } /* (non-Javadoc) * @see org.cast.cwm.service.IResponseService#attachBinaryResponse(org.apache.wicket.model.IModel, org.apache.wicket.markup.html.form.upload.FileUpload) */ @Override public IModel<BinaryFileData> attachBinaryResponse(IModel<Response> mResponse, FileUpload file) { // If the response is transient, create it // Otherwise, grab the if (mResponse.getObject().isTransient()) { saveResponseWithoutData(mResponse); } // Lock the Response LockRequest lock = Databinder.getHibernateSession().buildLockRequest(LockOptions.UPGRADE); lock.lock(mResponse.getObject()); // Upload file BinaryFileData dbFile = new BinaryFileData(file.getClientFileName(), file.getContentType(), file.getBytes()); Databinder.getHibernateSession().save(dbFile); // Associate File with Response mResponse.getObject().getFiles().add(dbFile); // Persist Changes cwmService.flushChanges(); return new HibernateObjectModel<BinaryFileData>(dbFile); } /* (non-Javadoc) * @see org.cast.cwm.service.IResponseService#saveSVGResponse(org.apache.wicket.model.IModel, java.lang.String, java.lang.String) */ @Override public void saveSVGResponse(IModel<Response> mResponse, String svg, String pageName) { saveTextResponse(mResponse, svg, pageName); } /* (non-Javadoc) * @see org.cast.cwm.service.IResponseService#saveFlashAudioResponse(org.apache.wicket.model.IModel, java.lang.String, java.lang.String) */ @Override public void saveFlashAudioResponse(IModel<Response> response, String audioId, String pageName) { saveTextResponse(response, audioId, pageName); // Flash audio just saves id in 3rd party server } /* (non-Javadoc) * @see org.cast.cwm.service.IResponseService#genericSaveResponse(org.apache.wicket.model.IModel, java.lang.String, java.lang.Integer, java.lang.Integer, java.lang.Integer, org.cast.cwm.data.BinaryFileData, java.lang.String) */ @Override public void genericSaveResponse(IModel<Response> mResponse, String text, Integer score, Integer attempted, Integer total, BinaryFileData bd, String pageName) { saveResponseWithoutData(mResponse); // Create and associate a new ResponseData object for this response // which will be saved via Cascade.ALL. ResponseData rd = mResponse.getObject().getNewResponseDataObject(); if (text != null) rd.setText(text); if (score != null) rd.setScore(score); if (attempted != null) rd.setAttempted(attempted); if (total != null) rd.setTotal(total); if (bd != null) { rd.setBinaryFileData(bd); } // Save (and keep a reference to) an event rd.setEvent(eventService.savePostEvent(true, pageName).getObject()); // Flush changes to datastore cwmService.flushChanges(); } /* (non-Javadoc) * @see org.cast.cwm.service.IResponseService#saveResponseWithoutData(org.apache.wicket.model.IModel) */ @Override public void saveResponseWithoutData(IModel<Response> mResponse) { cwmService.confirmDatastoreModel(mResponse); Response response = mResponse.getObject(); boolean checkBinding = false; // If the Response is new, save it. if (response.isTransient()) { if (response.getCreateDate() == null) response.setCreateDate(new Date()); Databinder.getHibernateSession().save(response); checkBinding = true; } cwmService.flushChanges(); if (checkBinding) { ((HibernateObjectModel<Response>) mResponse).checkBinding(); } } /* (non-Javadoc) * @see org.cast.cwm.service.IResponseService#setResponseSortOrder(org.apache.wicket.model.IModel, org.apache.wicket.model.IModel, java.lang.Integer) */ @Override public void setResponseSortOrder(IModel<? extends Prompt> mPrompt, IModel<Response> mResponse, Integer index) { // DataProvider for Responses for this Prompt. // It is assumed that the target Response is included in this list. ISortableDataProvider<Response, String> dataProvider = getResponseProviderForPrompt(mPrompt); dataProvider.getSortState().setPropertySortOrder("sortOrder", SortOrder.ASCENDING); if (index == null) index = (int) dataProvider.size() - 1; if (index < 0) throw new IllegalArgumentException("Index cannot be negative."); if (index >= (dataProvider.size())) throw new IndexOutOfBoundsException( "Index {" + index + "} exceeds the number of Responses {" + dataProvider.size() + "}."); Iterator<? extends Response> iterator = dataProvider.iterator(0, dataProvider.size()); int iteratorIndex = 0; boolean foundResponse = false; while (iterator.hasNext()) { Response r = iterator.next(); // Reached the target response if (r.equals(mResponse.getObject())) foundResponse = true; // Overwrite sortOrder; making room for insertion if necessary if (iteratorIndex >= index && !foundResponse) r.setSortOrder(iteratorIndex + 1); else r.setSortOrder(iteratorIndex); iteratorIndex++; } if (!foundResponse) throw new IllegalStateException("Unknown behavior - Response was not found in iterator."); mResponse.getObject().setSortOrder(index); cwmService.flushChanges(); } /* (non-Javadoc) * @see org.cast.cwm.service.IResponseService#deleteResponse(org.apache.wicket.model.IModel) */ @Override public void deleteResponse(IModel<Response> r) { cwmService.confirmDatastoreModel(r); // Do nothing for a transient Response object if (r.getObject().isTransient()) return; // "Delete" this response r.getObject().setValid(false); // Remove any ordering r.getObject().setSortOrder(null); // Flush changes to datastore cwmService.flushChanges(); eventService.saveEvent("post:delete", String.valueOf(r.getObject().getId()), null); } /* (non-Javadoc) * @see org.cast.cwm.service.IResponseService#getResponseById(java.lang.Long) */ @Override public IModel<Response> getResponseById(Long id) { return new ResponseModel(id); } /* (non-Javadoc) * @see org.cast.cwm.service.IResponseService#getPromptById(java.lang.Long) */ @Override public IModel<Prompt> getPromptById(Long id) { return new PromptModel(id); } }