Skip to content

Commit

Permalink
0002650: Support File Sync on Android.
Browse files Browse the repository at this point in the history
  • Loading branch information
mmichalek committed Jun 27, 2016
1 parent e4a475a commit 32a86bb
Show file tree
Hide file tree
Showing 8 changed files with 169 additions and 10 deletions.
@@ -0,0 +1,43 @@
/**
* Licensed to JumpMind Inc under one or more contributor
* license agreements. See the NOTICE file distributed
* with this work for additional information regarding
* copyright ownership. JumpMind Inc licenses this file
* to you under the GNU General Public License, version 3.0 (GPLv3)
* (the "License"); you may not use this file except in compliance
* with the License.
*
* You should have received a copy of the GNU General Public License,
* version 3.0 (GPLv3) along with this library; if not, see
* <http://www.gnu.org/licenses/>.
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jumpmind.symmetric.android;

import java.io.File;

import org.jumpmind.symmetric.ISymmetricEngine;
import org.jumpmind.symmetric.service.impl.FileSyncService;

import android.os.Environment;
import bsh.EvalError;
import bsh.Interpreter;

public class AndroidFileSyncService extends FileSyncService {

public AndroidFileSyncService(ISymmetricEngine engine) {
super(engine);
}

@Override
protected void setInterpreterVariables(ISymmetricEngine engine, String sourceNodeId, File batchDir, Interpreter interpreter) throws EvalError {
super.setInterpreterVariables(engine, sourceNodeId, batchDir, interpreter);
interpreter.set("androidBaseDir", Environment.getExternalStorageDirectory() + "/");
}
}
Expand Up @@ -52,6 +52,12 @@ public class AndroidJobManager implements IJobManager {
protected long lastPurgeTime = System.currentTimeMillis();

protected long lastRouteTime = System.currentTimeMillis();

protected long lastFileSyncPullTime = System.currentTimeMillis();

protected long lastFileSyncTrackerTime = System.currentTimeMillis();

protected long lastFileSyncPushTime = System.currentTimeMillis();

public AndroidJobManager(ISymmetricEngine engine) {
this.engine = engine;
Expand Down Expand Up @@ -183,6 +189,49 @@ public boolean invoke(boolean force) {
lastPurgeTime = System.currentTimeMillis();
}
}

if (parameterService.is(ParameterConstants.FILE_SYNC_ENABLE)
&& parameterService.is("start.file.sync.tracker.job")
&& parameterService.getLong("job.file.sync.tracker.period.time.ms", 5000) < (System
.currentTimeMillis() - lastFileSyncTrackerTime)) {
try {
didWork = true;
engine.getFileSyncService().trackChanges(false);
} catch (Throwable ex) {
log.error("", ex);
} finally {
lastFileSyncTrackerTime = System.currentTimeMillis();
}
}

if (parameterService.is(ParameterConstants.FILE_SYNC_ENABLE)
&& parameterService.is("start.file.sync.pull.job")
&& parameterService.getLong("job.file.sync.pull.period.time.ms", 60000) < (System
.currentTimeMillis() - lastFileSyncPullTime)) {
try {
didWork = true;
engine.getFileSyncService().pullFilesFromNodes(false);
} catch (Throwable ex) {
log.error("", ex);
} finally {
lastFileSyncPullTime = System.currentTimeMillis();
}
}

if (parameterService.is(ParameterConstants.FILE_SYNC_ENABLE)
&& parameterService.is("job.file.sync.push")
&& parameterService.getLong("job.file.sync.push.period.time.ms", 60000) < (System
.currentTimeMillis() - lastFileSyncPullTime)) {
try {

didWork = true;
engine.getFileSyncService().pushFilesToNodes(false);
} catch (Throwable ex) {
log.error("", ex);
} finally {
lastFileSyncPushTime = System.currentTimeMillis();
}
}

} finally {
if (didWork) {
Expand Down
Expand Up @@ -48,6 +48,7 @@
import org.jumpmind.symmetric.service.IClusterService;
import org.jumpmind.symmetric.service.IConfigurationService;
import org.jumpmind.symmetric.service.IExtensionService;
import org.jumpmind.symmetric.service.IFileSyncService;
import org.jumpmind.symmetric.service.IMonitorService;
import org.jumpmind.symmetric.service.INodeCommunicationService;
import org.jumpmind.symmetric.service.INodeService;
Expand Down Expand Up @@ -82,6 +83,15 @@ public AndroidSymmetricEngine(String registrationUrl, String externalId, String
init();
}

protected void init() {
super.init();
if (symmetricDialect instanceof SqliteSymmetricDialect) {
//
SqliteSymmetricDialect sqliteDialect = (SqliteSymmetricDialect)symmetricDialect;
sqliteDialect.setContextService(contextService);
}
}

@Override
protected SecurityServiceType getSecurityServiceType() {
return SecurityServiceType.CLIENT;
Expand Down Expand Up @@ -126,7 +136,7 @@ public Collection<String> getResourceReferences() {

@Override
protected ISymmetricDialect createSymmetricDialect() {
return new SqliteSymmetricDialect(parameterService, contextService, platform);
return new SqliteSymmetricDialect(parameterService, platform);
}

@Override
Expand All @@ -143,6 +153,11 @@ protected IExtensionService createExtensionService() {
protected IRouterService buildRouterService() {
return new AndroidRouterService(this);
}

@Override
protected IFileSyncService buildFileSyncService() {
return new AndroidFileSyncService(this);
}

class AndroidRouterService extends RouterService {

Expand Down
Expand Up @@ -13,7 +13,8 @@
public class SqliteJdbcSymmetricDialect extends SqliteSymmetricDialect {

public SqliteJdbcSymmetricDialect(IParameterService parameterService, IContextService contextService, IDatabasePlatform platform) {
super(parameterService, contextService, platform);
super(parameterService, platform);
setContextService(contextService);
}

@Override
Expand Down
Expand Up @@ -353,9 +353,10 @@ protected void init() {
this.offlinePullService = new OfflinePullService(parameterService, symmetricDialect,
nodeService, dataLoaderService, clusterService, nodeCommunicationService,
configurationService, extensionService, offlineTransportManager);
this.fileSyncService = new FileSyncService(this);
this.fileSyncService = buildFileSyncService();
this.mailService = new MailService(parameterService, symmetricDialect);
this.contextService = new ContextService(parameterService, symmetricDialect);

this.jobManager = createJobManager();

extensionService.addExtensionPoint(new DefaultOfflineServerListener(
Expand All @@ -375,6 +376,10 @@ protected void init() {
protected IRouterService buildRouterService() {
return new RouterService(this);
}

protected IFileSyncService buildFileSyncService() {
return new FileSyncService(this);
}

protected INodeCommunicationService buildNodeCommunicationService(IClusterService clusterService, INodeService nodeService, IParameterService parameterService,
IConfigurationService configurationService, ISymmetricDialect symmetricDialect) {
Expand Down
Expand Up @@ -27,6 +27,7 @@
import org.jumpmind.db.sql.ISqlTransaction;
import org.jumpmind.db.sql.SqlException;
import org.jumpmind.db.util.BinaryEncoding;
import org.jumpmind.symmetric.SymmetricException;
import org.jumpmind.symmetric.common.ParameterConstants;
import org.jumpmind.symmetric.common.TableConstants;
import org.jumpmind.symmetric.db.AbstractSymmetricDialect;
Expand All @@ -43,13 +44,16 @@ public class SqliteSymmetricDialect extends AbstractSymmetricDialect {

String sqliteFunctionToOverride;

public SqliteSymmetricDialect(IParameterService parameterService, IContextService contextService, IDatabasePlatform platform) {
public SqliteSymmetricDialect(IParameterService parameterService, IDatabasePlatform platform) {
super(parameterService, platform);
this.contextService = contextService;
this.triggerTemplate = new SqliteTriggerTemplate(this);
sqliteFunctionToOverride = parameterService.getString(ParameterConstants.SQLITE_TRIGGER_FUNCTION_TO_USE);
}

public void setContextService(IContextService contextService) {
this.contextService = contextService;
}

@Override
public void createRequiredDatabaseObjects() {
}
Expand All @@ -66,6 +70,10 @@ protected void setSqliteFunctionResult(ISqlTransaction transaction, final String

public void disableSyncTriggers(ISqlTransaction transaction, String nodeId) {
if (isBlank(sqliteFunctionToOverride)) {
if (contextService == null) {
throw new SymmetricException("contextService can't be null by this point. "
+ "Please provide a non-null contextService before using this functionality.");
}
contextService.insert(transaction, SYNC_TRIGGERS_DISABLED_USER_VARIABLE, "1");
if (nodeId != null) {
contextService.insert(transaction, SYNC_TRIGGERS_DISABLED_NODE_VARIABLE, nodeId);
Expand All @@ -78,6 +86,10 @@ public void disableSyncTriggers(ISqlTransaction transaction, String nodeId) {

public void enableSyncTriggers(ISqlTransaction transaction) {
if (isBlank(sqliteFunctionToOverride)) {
if (contextService == null) {
throw new SymmetricException("contextService can't be null by this point. "
+ "Please provide a non-null contextService before using this functionality.");
}
contextService.delete(transaction, SYNC_TRIGGERS_DISABLED_USER_VARIABLE);
contextService.delete(transaction, SYNC_TRIGGERS_DISABLED_NODE_VARIABLE);
} else {
Expand Down
Expand Up @@ -169,6 +169,12 @@ public void end(Batch batch, boolean inError) {
targetBaseDir = StringEscapeUtils.escapeJava(targetBaseDir);

command.append("targetBaseDir = \"").append(targetBaseDir).append("\";\n");

command.append("if (targetBaseDir.startsWith(\"${androidBaseDir}\")) { \n");
command.append(" targetBaseDir = targetBaseDir.replace(\"${androidBaseDir}\", \"\"); \n");
command.append(" targetBaseDir = androidBaseDir + targetBaseDir; \n");
command.append("} \n");

command.append("processFile = true;\n");
command.append("sourceFileName = \"").append(snapshot.getFileName())
.append("\";\n");
Expand Down Expand Up @@ -357,5 +363,21 @@ public void finish() {
public boolean readyToSend() {
return byteCount > maxBytesToSync;
}

// public static void main(String[] args) {
// String androidBaseDir = "/emulated/0/";
//
// String targetBaseDir = "${androidBaseDir}/manuals";
// if (targetBaseDir.startsWith("${androidBaseDir}")) {
// targetBaseDir = targetBaseDir.replace("${androidBaseDir}", "");
// targetBaseDir = androidBaseDir + targetBaseDir;
// }
// System.out.println(targetBaseDir);
//
//
//
// //command.append("targetBaseDir = \"").append(targetBaseDir).append("\";\n");
//// command.append("targetBaseDir.replaceAll(\"${androidBaseDir}\", \" + androidBaseDir + \"); ;\n");
// }

}
Expand Up @@ -709,7 +709,15 @@ protected List<IncomingBatch> processZip(InputStream is, String sourceNodeId,
FileUtils.deleteDirectory(unzipDir);
unzipDir.mkdirs();

AppUtils.unzip(is, unzipDir);
try {
AppUtils.unzip(is, unzipDir);
} catch (IoException ex) {
if (ex.toString().contains("EOFException")) { // This happens on Android, when there is an empty zip.
//log.debug("Caught exception while unzipping.", ex);
} else {
throw ex;
}
}

Set<Long> batchIds = new TreeSet<Long>();
String[] files = unzipDir.list(DirectoryFileFilter.INSTANCE);
Expand Down Expand Up @@ -762,10 +770,7 @@ protected List<IncomingBatch> processZip(InputStream is, String sourceNodeId,
Interpreter interpreter = new Interpreter();
boolean isLocked = false;
try {
interpreter.set("log", log);
interpreter.set("batchDir", batchDir.getAbsolutePath().replace('\\', '/'));
interpreter.set("engine", engine);
interpreter.set("sourceNodeId", sourceNodeId);
setInterpreterVariables(engine, sourceNodeId, batchDir, interpreter);

long waitMillis = getParameterService().getLong(
ParameterConstants.FILE_SYNC_LOCK_WAIT_MS);
Expand Down Expand Up @@ -839,6 +844,13 @@ protected List<IncomingBatch> processZip(InputStream is, String sourceNodeId,

return batchesProcessed;
}

protected void setInterpreterVariables(ISymmetricEngine engine, String sourceNodeId, File batchDir, Interpreter interpreter) throws EvalError {
interpreter.set("log", log);
interpreter.set("batchDir", batchDir.getAbsolutePath().replace('\\', '/'));
interpreter.set("engine", engine);
interpreter.set("sourceNodeId", sourceNodeId);
}

protected void updateFileIncoming(String nodeId, Map<String, String> filesToEventType) {
Set<String> filePaths = filesToEventType.keySet();
Expand Down

0 comments on commit 32a86bb

Please sign in to comment.