Java tutorial
/******************************************************************************* * Copyright (c) 2014,2015 Hideki Yatomi * All rights reserved. This program and the accompanying materials are made * available under the terms of the Eclipse Public License v1.0 which * accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html ******************************************************************************/ package net.yatomiya.nicherry.services.bbs; import java.io.*; import java.util.*; import org.eclipse.swt.*; import org.eclipse.swt.graphics.*; import com.squareup.okhttp.*; import net.yatomiya.e4.ui.dialogs.*; import net.yatomiya.e4.util.*; import net.yatomiya.nicherry.*; import net.yatomiya.nicherry.model.bbs.*; import net.yatomiya.nicherry.services.bbs.model.*; public class ThreadUpdateHandler extends ModelUpdateHandler { boolean isDeltaGetSuccess; byte[] contents; byte[] sjisDat; String downloadedDatText; List<MMessage> downloadedMessages; ThreadUpdateHandler() { super(); isDeltaGetSuccess = false; contents = new byte[0]; sjisDat = new byte[0]; } @Override public ThreadProcessor getProcessor() { return (ThreadProcessor) super.getProcessor(); } @Override public MThread getModel() { return (MThread) super.getModel(); } @Override public ThreadUpdateEvent getUpdateEvent() { return (ThreadUpdateEvent) super.getUpdateEvent(); } @Override protected UpdateEvent createUpdateEvent() { return new ThreadUpdateEvent(); } @Override protected String createRequestUrl() { MBoard board = getProcessor().getManager().getBBSService().getBoard(getModel().getId().getBoardId()); if (board == null) return ""; return board.getUrl() + "dat/" + getModel().getDatKey() + ".dat"; } Response processIntercept(Interceptor.Chain chain) throws IOException { Response response = null; Request.Builder builder = chain.request().newBuilder(); if (!isForceUpdate()) { // try delta get. byte[] tail = getProcessor().getDatTail().getTail(); if (tail.length > 0) { File datFile = getProcessor().getDatFile(); if (IOUtils.isFileExists(datFile)) { long datLen = datFile.length(); if (datLen > 0) { long getStartOffset = datLen - tail.length; if (getStartOffset > 0) { builder.header("Range", "bytes=" + getStartOffset + "-"); // Disable gzip compression. Gzip compression and partial get can't co-exist. // Header with empty value must be set. If header is not set, HttpClient default implementation // adds header with value accepting gzip format automatically. builder.header("Accept-Encoding", ""); response = chain.proceed(builder.build()); switch (response.code()) { case 200: // OK case 206: // Partial Content // check contents. contents = response.body().bytes(); if (contents.length < tail.length || !Arrays.equals(tail, Arrays.copyOfRange(contents, 0, tail.length))) { // Tail data of local dat is different from server, we must get whole dat. // That means local dat is NOT identical to dat in server, something is modified in server. // So we must get whole dat from server again. // If region except stored in tail is modified in server, and length of dat in server equals to dat in local, // we can't find out those differences. contents = null; } else { // delta contents is valid. isDeltaGetSuccess = true; return response; } break; case 304: // Not Modified // Not modified, so no need to update. return response; case 416: // Range Not Satisfied default: // Failed. break; } } } } } } // do get all return chain.proceed(chain.request()); } @Override protected boolean handleValidateResponse(Response response) { if (isDeltaGetSuccess && response.code() == 206) { return true; } return super.handleValidateResponse(response); } @Override protected boolean handleBackground(Response response) throws IOException { int noOffset; if (isDeltaGetSuccess) { // content is already loaded when delta get. sjisDat = Arrays.copyOfRange(contents, getProcessor().getDatTail().getTail().length, contents.length); noOffset = getModel().getMessages().size(); } else { contents = response.body().bytes(); sjisDat = contents; noOffset = 0; } downloadedDatText = StringUtils.getString(sjisDat, NConstants.CHARSET_SHIFT_JIS); downloadedMessages = new DatParser().parse(getModel(), downloadedDatText, noOffset); if (sjisDat.length <= 0) { // http code is not 'Not modified', but no data was sent in response body. getUpdateEvent().setType(UpdateEvent.Type.NOT_MODIFIED); return false; } return true; } @Override protected boolean handleForeground() throws IOException { MThread thread = getModel(); List<MMessage> msgs = getModel().getMessages(); boolean wholeChanged = false; // ????????? dat ????????? if (!isDeltaGetSuccess) { if (msgs.size() > 0) { int matchedCount = 0; for (int i = 0; i < msgs.size(); i++) { if (i < downloadedMessages.size() && BBSUtils.messageEquals(msgs.get(i), downloadedMessages.get(i))) { matchedCount++; } } if (matchedCount == 0) wholeChanged = true; /* if (matchedCount != msgs.size()) { boolean result = askIfOverrideDat(getModel(), downloadedDatText); if (!result) return false; } */ } } if (wholeChanged) { getModel().getPostMessageRecordList().clear(); } getProcessor().getDatTail().set(sjisDat); IOUtils.write(getProcessor().getDatFile(), sjisDat, isDeltaGetSuccess); List<MMessage> oldMessages = new ArrayList<>(msgs); if (!isDeltaGetSuccess) msgs.clear(); msgs.addAll(downloadedMessages); int lastCount = thread.getMessageCount(); if (wholeChanged) lastCount = 0; thread.setLastMessageCount(lastCount); thread.setMessageCount(msgs.size()); // Get thread title from message No.1. if (JUtils.isEmpty(thread.getName()) && msgs.size() > 0) { thread.setName(msgs.get(0).getExtText()); } if (isDeltaGetSuccess) { AnalyzedThread at = getProcessor().getAnalyzedThread(); at.addMessages(downloadedMessages); } else { getProcessor().resetAnalyzedStates(); } getProcessor().checkIfPostMessageIsUpdatedInDat(); ThreadUpdateEvent event = getUpdateEvent(); event.setDeltaGet(isDeltaGetSuccess); event.setOldMessages(oldMessages); event.setDownloadedMessages(downloadedMessages); return true; } @Override protected String getFinishedAnnounceMessage() { return ""; } private boolean askIfOverrideDat(MThread thread, String newDatText) { TextMessageDialog dlg = new TextMessageDialog(null, TextMessageDialog.Type.WARNING, String.format("dat ??? : %s", BBSUtils.getPathName(thread)), "? dat ???? dat ?????\n" + "?????????\n" + "\n" + newDatText, SWT.READ_ONLY | SWT.H_SCROLL | SWT.V_SCROLL) { @Override protected Point getInitialSize() { return new Point(600, 400); } }; int result = dlg.open(); return result == TextMessageDialog.OK; } }