/* ############################################################################### # # # Copyright (C) 2011-2016 OpenMEAP, Inc. # # Credits to Jonathan Schang & Rob Thacher # # # # Released under the LGPLv3 # # # # OpenMEAP is free software: you can redistribute it and/or modify # # it under the terms of the GNU Lesser General Public License as published # # by the Free Software Foundation, either version 3 of the License, or # # (at your option) any later version. # # # # OpenMEAP 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 Lesser General Public License for more details. # # # # You should have received a copy of the GNU Lesser General Public License # # along with OpenMEAP. If not, see <http://www.gnu.org/licenses/>. # # # ############################################################################### */ package com.openmeap.services; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.openmeap.digest.DigestException; import com.openmeap.http.HttpRequestExecuter; import com.openmeap.model.ModelManager; import com.openmeap.model.dto.Application; import com.openmeap.model.dto.ApplicationArchive; import com.openmeap.model.dto.ApplicationVersion; import com.openmeap.model.dto.Deployment; import com.openmeap.model.dto.GlobalSettings; import com.openmeap.protocol.ApplicationManagementService; import com.openmeap.protocol.WebServiceException; import com.openmeap.protocol.dto.ConnectionOpenRequest; import com.openmeap.protocol.dto.ConnectionOpenResponse; import com.openmeap.protocol.dto.Hash; import com.openmeap.protocol.dto.HashAlgorithm; import com.openmeap.protocol.dto.UpdateHeader; import com.openmeap.protocol.dto.UpdateNotification; import com.openmeap.protocol.dto.UpdateType; import com.openmeap.util.AuthTokenProvider; import com.openmeap.util.GenericRuntimeException; /** * Server-side implementation of the ApplicationManagementService * * @author schang */ public class ApplicationManagementServiceImpl implements ApplicationManagementService { Logger logger = LoggerFactory.getLogger(ApplicationManagementServiceImpl.class); private ModelManager modelManager = null; /** * Set the ModelManager for the service to use when handling CRUD operations. * * @param modelManager */ public void setModelManager(ModelManager modelManager) { this.modelManager = modelManager; } public ModelManager getModelManager() { return modelManager; } public ConnectionOpenResponse connectionOpen(ConnectionOpenRequest request) throws WebServiceException { String reqAppArchHashVal = StringUtils.trimToNull(request.getApplication().getHashValue()); String reqAppVerId = StringUtils.trimToNull(request.getApplication().getVersionId()); String reqAppName = StringUtils.trimToNull(request.getApplication().getName()); ConnectionOpenResponse response = new ConnectionOpenResponse(); GlobalSettings settings = modelManager.getGlobalSettings(); if( StringUtils.isBlank(settings.getExternalServiceUrlPrefix()) && logger.isWarnEnabled() ) { logger.warn("The external service url prefix configured in the admin interface is blank. " +"This will probably cause issues downloading application archives."); } Application application = getApplication(reqAppName,reqAppVerId); // Generate a new auth token for the device to present to the proxy String authToken; try { authToken = AuthTokenProvider.newAuthToken(application.getProxyAuthSalt()); } catch (DigestException e) { throw new GenericRuntimeException(e); } response.setAuthToken(authToken); // If there is a deployment, // and the version of that deployment differs in hash value or identifier // then return an update in the response Deployment lastDeployment = modelManager.getModelService().getLastDeployment(application); Boolean reqAppVerDiffers = lastDeployment!=null && !lastDeployment.getVersionIdentifier().equals(reqAppVerId); Boolean reqAppArchHashValDiffers = lastDeployment!=null && reqAppArchHashVal!=null && !lastDeployment.getApplicationArchive().getHash().equals(reqAppArchHashVal); // we only send an update if // a deployment has been made // and one of the following is true // the app version is different than reported // the app hash value is different than reported if( reqAppVerDiffers || reqAppArchHashValDiffers ) { // TODO: I'm not happy with the discrepancies between the model and schema // ...besides, this update header should be encapsulated somewhere else ApplicationArchive currentVersionArchive = lastDeployment.getApplicationArchive(); UpdateHeader uh = new UpdateHeader(); uh.setVersionIdentifier(lastDeployment.getVersionIdentifier()); uh.setInstallNeeds(Long.valueOf(currentVersionArchive.getBytesLength()+currentVersionArchive.getBytesLengthUncompressed())); uh.setStorageNeeds(Long.valueOf(currentVersionArchive.getBytesLengthUncompressed())); uh.setType( UpdateType.fromValue(lastDeployment.getType().toString()) ); uh.setUpdateUrl(currentVersionArchive.getDownloadUrl(settings)); uh.setHash(new Hash()); uh.getHash().setAlgorithm( HashAlgorithm.fromValue( currentVersionArchive.getHashAlgorithm())); uh.getHash().setValue(currentVersionArchive.getHash()); response.setUpdate(uh); } return response; } public void notifyUpdateResult(UpdateNotification notification) throws WebServiceException { // if the application is tracking this, // then flip a flag in the database // and run rules } /* * PRIVATE METHODS */ private Application getApplication(String appName, String appVersionId) throws WebServiceException { if( appName==null || appVersionId==null ) { throw new WebServiceException(WebServiceException.TypeEnum.APPLICATION_VERSION_NOTFOUND, "Both application name and version id must be specified."); } ModelManager manager = getModelManager(); // we will need to verify that they have the latest version Application application = manager.getModelService().findApplicationByName(appName); if( application==null ) { throw new WebServiceException(WebServiceException.TypeEnum.APPLICATION_NOTFOUND, "The application \""+appName+"\" was not found."); } return application; } private HttpRequestExecuter executer = null; private String serviceUrl = null; @Override public void setServiceUrl(String serviceUrl) { this.serviceUrl = serviceUrl; } @Override public void setHttpRequestExecuter(HttpRequestExecuter executer) { this.executer = executer; } }