List of usage examples for java.util LinkedList clear
public void clear()
From source file:org.opendaylight.vtn.manager.it.northbound.VtnNorthboundIT.java
/** * Test case for MAC mapping APIs.//www .j a v a 2 s .co m * * <p> * This method is called by {@link #testVBridgeAPI(String, String)}. * </p> * * @param tname The name of existing virtual tenant. * @param bname1 The name of existing vBridge. * @param bname2 The name of existing vBridge. * @throws JSONException An error occurred. */ private void testMacMappingAPI(String tname, String bname1, String bname2) throws JSONException { LOG.info("Starting MAC Mapping JAX-RS client."); String qparam = "?param1=1¶m2=2"; String mapUri = createURI("default/vtns", tname, "vbridges", bname1, "macmap"); String mapUri2 = createURI("default/vtns", tname, "vbridges", bname2, "macmap"); // Ensure that no MAC mapping is configured. assertNoMacMapping(mapUri); assertNoMacMapping(mapUri2); LinkedList<String> allowedHosts = new LinkedList<String>(); allowedHosts.add(null); allowedHosts.add(null); byte[] allowedAddr = { (byte) 0x10, (byte) 0x20, (byte) 0x30, (byte) 0x40, (byte) 0x50, (byte) 0x00, }; for (int i = 0; i < 20; i++) { String mac; if ((i & 1) == 0) { mac = null; } else { allowedAddr[5] = (byte) i; mac = ByteUtils.toHexString(allowedAddr); } String vlan = (i == 0) ? "4095" : String.valueOf(i); allowedHosts.add(mac); allowedHosts.add(vlan); } LinkedList<String> deniedHosts = new LinkedList<String>(); byte[] deniedAddr = { (byte) 0xf0, (byte) 0xf1, (byte) 0xf2, (byte) 0xf3, (byte) 0x00, (byte) 0xf5, }; for (int i = 0; i < 20; i++) { deniedAddr[4] = (byte) i; String mac = ByteUtils.toHexString(deniedAddr); String vlan = String.valueOf(i + 100); deniedHosts.add(mac); deniedHosts.add(vlan); } deniedHosts.add("00:00:ff:ff:ff:0f"); deniedHosts.add(null); // Install MAC mapping configuration. JSONObject config = createMacMapConfig(allowedHosts, deniedHosts); JSONObject configExpected = completeMacMapConfig(config); String cf = config.toString(); getJsonResult(mapUri + qparam, HTTP_PUT, cf); assertResponse(HTTP_CREATED); Assert.assertEquals(mapUri, httpLocation); for (String method : new String[] { HTTP_PUT, HTTP_POST }) { getJsonResult(mapUri, method, cf); assertResponse(HTTP_NO_CONTENT); } assertMacMapping(mapUri, configExpected); // Try to create MAC mapping with specifying invalid MAC address. String[] badMacs = { // broken "invalid_mac_address", // zero "00:00:00:00:00:00", // broadcast "ff:ff:ff:ff:ff:ff", // multicast "81:00:11:22:33:44", }; String[] acls = { "allow", "deny" }; for (String mac : badMacs) { JSONObject machost = new JSONObject(); machost.put("address", mac); machost.put("vlan", 1); JSONArray maclist = new JSONArray(); maclist.put(machost); JSONObject set = new JSONObject(); set.put("machost", maclist); for (String acl : acls) { String uri = createRelativeURI(mapUri, acl, mac, "1"); getJsonResult(uri, HTTP_PUT); assertResponse(HTTP_BAD_REQUEST); for (String method : new String[] { HTTP_PUT, HTTP_POST }) { JSONObject conf = new JSONObject(); conf.put(acl, set); getJsonResult(mapUri, method, conf.toString()); assertResponse(HTTP_BAD_REQUEST); uri = createRelativeURI(mapUri, acl); getJsonResult(uri, method, set.toString()); assertResponse(HTTP_BAD_REQUEST); } } } // Try to create MAC mapping with specifying invalid VLAN ID. int[] badVlans = { -1, 4096, 10000, }; for (int vlan : badVlans) { String mac = "00:00:00:00:00:10"; JSONObject machost = new JSONObject(); machost.put("address", mac); machost.put("vlan", vlan); JSONArray maclist = new JSONArray(); maclist.put(machost); JSONObject set = new JSONObject(); set.put("machost", maclist); for (String acl : acls) { String uri = createRelativeURI(mapUri, acl, mac, String.valueOf(vlan)); getJsonResult(uri, HTTP_PUT); assertResponse(HTTP_BAD_REQUEST); for (String method : new String[] { HTTP_PUT, HTTP_POST }) { JSONObject conf = new JSONObject(); conf.put(acl, set); getJsonResult(mapUri, method, conf.toString()); assertResponse(HTTP_BAD_REQUEST); uri = createRelativeURI(mapUri, acl); getJsonResult(uri, method, set.toString()); assertResponse(HTTP_BAD_REQUEST); } } } // Try to register NULL address to deny set. for (String method : new String[] { HTTP_POST, HTTP_PUT }) { String acl = "deny"; JSONObject set = createMacHostSet(null, "110"); JSONObject conf = new JSONObject(); conf.put(acl, set); getJsonResult(mapUri, method, conf.toString()); assertResponse(HTTP_BAD_REQUEST); String uri = createRelativeURI(mapUri, acl); getJsonResult(uri, method, set.toString()); assertResponse(HTTP_BAD_REQUEST); } // Try to remove hosts that are not registered. String remove = "?action=remove"; LinkedList<String> allowedHosts1 = new LinkedList<String>(); for (int i = 0; i < 5; i++) { String mac; if ((i & 1) == 0) { mac = null; } else { allowedAddr[5] = (byte) i; mac = ByteUtils.toHexString(allowedAddr); } String vlan = String.valueOf(i + 100); allowedHosts1.add(mac); allowedHosts1.add(vlan); } for (int i = 5; i < 10; i++) { String mac; if ((i & 1) == 0) { allowedAddr[5] = (byte) (i + 1); mac = ByteUtils.toHexString(allowedAddr); } else { mac = null; } String vlan = String.valueOf(i); allowedHosts1.add(mac); allowedHosts1.add(vlan); } LinkedList<String> deniedHosts1 = new LinkedList<String>(); for (int i = 0; i < 5; i++) { deniedAddr[4] = (byte) (i + 1); String mac = ByteUtils.toHexString(deniedAddr); String vlan = String.valueOf(i + 100); deniedHosts1.add(mac); deniedHosts1.add(vlan); } for (int i = 5; i < 10; i++) { deniedAddr[4] = (byte) i; String mac = ByteUtils.toHexString(deniedAddr); String vlan = String.valueOf(i + 1000); deniedHosts1.add(mac); deniedHosts1.add(vlan); } JSONObject allow1 = createMacHostSet(allowedHosts1); JSONObject deny1 = createMacHostSet(deniedHosts1); config = new JSONObject(); config.put("allow", allow1).put("deny", deny1); getJsonResult(createRelativeURI(mapUri + remove), HTTP_POST, config.toString()); assertResponse(HTTP_NO_CONTENT); for (String acl : acls) { JSONObject set; LinkedList<String> hostList; if (acl.equals("allow")) { set = allow1; hostList = allowedHosts1; } else { set = deny1; hostList = deniedHosts1; } getJsonResult(createRelativeURI(mapUri, acl + remove), HTTP_POST, set.toString()); assertResponse(HTTP_NO_CONTENT); Iterator<String> it = hostList.iterator(); while (it.hasNext()) { String m = it.next(); String v = it.next(); String uri = createRelativeURI(mapUri, acl, (m == null) ? "ANY" : m, (v == null) ? "0" : v); getJsonResult(uri, HTTP_DELETE); assertResponse(HTTP_NO_CONTENT); } } String[] allowedArray = allowedHosts.toArray(new String[0]); for (int i = 0; i < allowedArray.length; i += 2) { String acl = "allow"; String mac = allowedArray[i]; String vlan = allowedArray[i + 1]; // Try to map MAC addresses which are already mapped by another // vBridge. String uri = createRelativeURI(mapUri2, acl, (mac == null) ? "ANY" : mac, (vlan == null) ? "0" : vlan); getJsonResult(uri, HTTP_PUT); assertResponse(HTTP_CONFLICT); JSONObject set = createMacHostSet(mac, vlan); JSONObject conf = new JSONObject(); conf.put(acl, set); for (String method : new String[] { HTTP_POST, HTTP_PUT }) { getJsonResult(mapUri2, method, conf.toString()); assertResponse(HTTP_CONFLICT); uri = createRelativeURI(mapUri2, acl); getJsonResult(uri, method, set.toString()); assertResponse(HTTP_CONFLICT); } if (mac == null) { continue; } // Try to register duplicate MAC address. uri = createRelativeURI(mapUri, acl, mac, "1000"); getJsonResult(uri, HTTP_PUT); assertResponse(HTTP_CONFLICT); set = createMacHostSet(mac, "1000"); conf = new JSONObject(); conf.put(acl, set); String method = HTTP_POST; getJsonResult(mapUri, method, conf.toString()); assertResponse(HTTP_CONFLICT); uri = createRelativeURI(mapUri, acl); getJsonResult(uri, method, set.toString()); assertResponse(HTTP_CONFLICT); } // Duplicate MAC address in allow set. String acl = "allow"; String mac = "00:11:22:33:55:88"; JSONObject set = createMacHostSet(mac, "1000", mac, "1001"); for (String method : new String[] { HTTP_POST, HTTP_PUT }) { JSONObject conf = new JSONObject(); conf.put(acl, set); getJsonResult(mapUri, method, conf.toString()); assertResponse(HTTP_BAD_REQUEST); String uri = createRelativeURI(mapUri, acl); getJsonResult(uri, method, set.toString()); assertResponse(HTTP_BAD_REQUEST); } // Configuration should not be affected. assertMacMapping(mapUri, configExpected); // Remove 2 hosts from both list. for (int i = 0; i < 4; i++) { allowedHosts.removeFirst(); deniedHosts.removeFirst(); } config = createMacMapConfig(allowedHosts, deniedHosts); getJsonResult(mapUri, HTTP_PUT, config.toString()); assertResponse(HTTP_OK); configExpected = completeMacMapConfig(config); assertMacMapping(mapUri, configExpected); for (String acl1 : acls) { LinkedList<String> hostList = (acl1.equals("allow")) ? allowedHosts : deniedHosts; // Remove 2 hosts by specifying the list. String mac1 = hostList.removeFirst(); String vlan1 = hostList.removeFirst(); String mac2 = hostList.removeFirst(); String vlan2 = hostList.removeFirst(); JSONObject set1 = createMacHostSet(mac1, vlan1, mac2, vlan2); String uri = createRelativeURI(mapUri, acl1 + remove); getJsonResult(uri, HTTP_POST, set1.toString()); assertResponse(HTTP_OK); assertMacMapping(mapUri, allowedHosts, deniedHosts); } // Remove 2 hosts from both lists. config = new JSONObject(); for (String acl1 : acls) { LinkedList<String> hostList = (acl1.equals("allow")) ? allowedHosts : deniedHosts; String mac1 = hostList.removeFirst(); String vlan1 = hostList.removeFirst(); String mac2 = hostList.removeFirst(); String vlan2 = hostList.removeFirst(); JSONObject set1 = createMacHostSet(mac1, vlan1, mac2, vlan2); config.put(acl1, set1); } getJsonResult(mapUri + remove, HTTP_POST, config.toString()); assertResponse(HTTP_OK); assertMacMapping(mapUri, allowedHosts, deniedHosts); // Remove 3 hosts by DELETE. for (String acl1 : acls) { LinkedList<String> hostList = (acl1.equals("allow")) ? allowedHosts : deniedHosts; for (int i = 0; i < 3; i++) { String m = hostList.removeFirst(); String v = hostList.removeFirst(); String uri = createRelativeURI(mapUri, acl1, (m == null) ? "ANY" : m, (v == null) ? "0" : v); getJsonResult(uri, HTTP_DELETE); assertResponse(HTTP_OK); } } assertMacMapping(mapUri, allowedHosts, deniedHosts); // Remove 3 hosts, and add 4 hosts by PUT. byte[] base = { (byte) 0xa0, (byte) 0xa1, (byte) 0xa2, (byte) 0x00, (byte) 0xa4, (byte) 0xa5, }; for (String acl1 : acls) { LinkedList<String> hostList = (acl1.equals("allow")) ? allowedHosts : deniedHosts; for (int i = 0; i < 6; i++) { hostList.removeFirst(); } for (int i = 0; i < 4; i++) { base[3] = (byte) i; hostList.add(ByteUtils.toHexString(base)); hostList.add(String.valueOf(i + 500)); } } config = createMacMapConfig(allowedHosts, deniedHosts); configExpected = completeMacMapConfig(config); getJsonResult(mapUri, HTTP_PUT, config.toString()); assertResponse(HTTP_OK); assertMacMapping(mapUri, allowedHosts, deniedHosts); for (String acl1 : acls) { LinkedList<String> hostList = (acl1.equals("allow")) ? allowedHosts : deniedHosts; for (int i = 0; i < 6; i++) { hostList.removeFirst(); } for (int i = 20; i < 24; i++) { base[3] = (byte) i; hostList.add(ByteUtils.toHexString(base)); hostList.add(String.valueOf(i + 500)); } JSONObject set1 = createMacHostSet(hostList); getJsonResult(createRelativeURI(mapUri, acl1), HTTP_PUT, set1.toString()); assertResponse(HTTP_OK); assertMacMapping(mapUri, allowedHosts, deniedHosts); } // Remove MAC mapping by specifying host list. LinkedList<String> saveAllowed = new LinkedList<String>(allowedHosts); LinkedList<String> saveDenied = new LinkedList<String>(deniedHosts); for (int i = 0; i < acls.length; i++) { String acl1 = acls[i]; LinkedList<String> hostList = (acl1.equals("allow")) ? allowedHosts : deniedHosts; hostList.clear(); String uri = createRelativeURI(mapUri, acl1); getJsonResult(uri, HTTP_DELETE); assertResponse(HTTP_OK); if (i == acls.length - 1) { assertNoMacMapping(mapUri); } else { assertMacMapping(mapUri, allowedHosts, deniedHosts); } } // Install the same MAC mapping to another vBridge. config = createMacMapConfig(saveAllowed, saveDenied); configExpected = completeMacMapConfig(config); getJsonResult(mapUri2, HTTP_PUT, config.toString()); assertResponse(HTTP_CREATED); assertMacMapping(mapUri2, configExpected); getJsonResult(mapUri2, HTTP_DELETE); assertResponse(HTTP_OK); assertNoMacMapping(mapUri2); // Create MAC mapping by installing a host to the specific URI. mac = "00:11:22:33:44:55"; String vlan = "4095"; JSONObject hostSet = createMacHostSet(mac, vlan); List<String> empty = new LinkedList<String>(); for (String acl1 : acls) { JSONObject set1; if (acl1.equals("allow")) { set1 = createMacHostSet(saveAllowed); config = createMacMapConfig(saveAllowed, empty); } else { set1 = createMacHostSet(saveDenied); config = createMacMapConfig(empty, saveDenied); } configExpected = completeMacMapConfig(config); String uri = createRelativeURI(mapUri2, acl1); for (String method : new String[] { HTTP_PUT, HTTP_POST }) { getJsonResult(uri + qparam, method, set1.toString()); assertResponse(HTTP_CREATED); Assert.assertEquals(uri, httpLocation); assertMacMapping(mapUri2, configExpected); getJsonResult(uri, HTTP_DELETE); assertResponse(HTTP_OK); assertNoMacMapping(mapUri2); } config = new JSONObject(); config.put(acl1, hostSet); String hostUri = createRelativeURI(uri, mac, vlan); getJsonResult(hostUri + qparam, HTTP_PUT); assertResponse(HTTP_CREATED); Assert.assertEquals(hostUri, httpLocation); assertMacMapping(mapUri2, config); getJsonResult(hostUri, HTTP_DELETE); assertResponse(HTTP_OK); assertNoMacMapping(mapUri2); } }
From source file:edu.mit.mobile.android.locast.sync.SyncEngine.java
/** * @param toSync//from ww w . ja va 2s .c o m * @param account * @param extras * @param provider * @param syncResult * @return true if the item was sync'd successfully. Soft errors will cause this to return * false. * @throws RemoteException * @throws SyncException * @throws JSONException * @throws IOException * @throws NetworkProtocolException * @throws NoPublicPath * @throws OperationApplicationException * @throws InterruptedException */ public boolean sync(Uri toSync, Account account, Bundle extras, ContentProviderClient provider, SyncResult syncResult) throws RemoteException, SyncException, JSONException, IOException, NetworkProtocolException, NoPublicPath, OperationApplicationException, InterruptedException { String pubPath = null; // // Handle http or https uris separately. These require the // destination uri. // if ("http".equals(toSync.getScheme()) || "https".equals(toSync.getScheme())) { pubPath = toSync.toString(); if (!extras.containsKey(EXTRA_DESTINATION_URI)) { throw new IllegalArgumentException("missing EXTRA_DESTINATION_URI when syncing HTTP URIs"); } toSync = Uri.parse(extras.getString(EXTRA_DESTINATION_URI)); } final String type = provider.getType(toSync); final boolean isDir = type.startsWith(CONTENT_TYPE_PREFIX_DIR); final boolean manualSync = extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false); // skip any items already sync'd if (!manualSync && mLastUpdated.isUpdatedRecently(toSync)) { if (DEBUG) { Log.d(TAG, "not syncing " + toSync + " as it's been updated recently"); } syncResult.stats.numSkippedEntries++; return false; } // the sync map will convert the json data to ContentValues final SyncMap syncMap = MediaProvider.getSyncMap(provider, toSync); final Uri toSyncWithoutQuerystring = toSync.buildUpon().query(null).build(); final HashMap<String, SyncStatus> syncStatuses = new HashMap<String, SyncEngine.SyncStatus>(); final ArrayList<ContentProviderOperation> cpo = new ArrayList<ContentProviderOperation>(); final LinkedList<String> cpoPubUris = new LinkedList<String>(); // // first things first, upload any content that needs to be // uploaded. // try { uploadUnpublished(toSync, account, provider, syncMap, syncStatuses, syncResult); if (Thread.interrupted()) { throw new InterruptedException(); } // this should ensure that all items have a pubPath when we // query it below. if (pubPath == null) { // we should avoid calling this too much as it // can be expensive pubPath = MediaProvider.getPublicPath(mContext, toSync); } } catch (final NoPublicPath e) { // TODO this is a special case and this is probably not the best place to handle this. // Ideally, this should be done in such a way as to reduce any extra DB queries - // perhaps by doing a join with the parent. if (syncMap.isFlagSet(SyncMap.FLAG_PARENT_MUST_SYNC_FIRST)) { if (DEBUG) { Log.d(TAG, "skipping " + toSync + " whose parent hasn't been sync'd first"); } syncResult.stats.numSkippedEntries++; return false; } // if it's an item, we can handle it. if (isDir) { throw e; } } if (pubPath == null) { // this should have been updated already by the initial // upload, so something must be wrong throw new SyncException("never got a public path for " + toSync); } if (DEBUG) { Log.d(TAG, "sync(toSync=" + toSync + ", account=" + account + ", extras=" + extras + ", manualSync=" + manualSync + ",...)"); Log.d(TAG, "pubPath: " + pubPath); } final long request_time = System.currentTimeMillis(); HttpResponse hr = mNetworkClient.get(pubPath); final long response_time = System.currentTimeMillis(); // the time compensation below allows a time-based synchronization to function even if the // local clock is entirely wrong. The server's time is extracted using the Date header and // all are compared relative to the respective clock reference. Any data that's stored on // the mobile should be stored relative to the local clock and the server will respect the // same. long serverTime; try { serverTime = getServerTime(hr); } catch (final DateParseException e) { Log.w(TAG, "could not retrieve date from server. Using local time, which may be incorrect.", e); serverTime = System.currentTimeMillis(); } // TODO check out // http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html final long response_delay = response_time - request_time; if (DEBUG) { Log.d(TAG, "request took " + response_delay + "ms"); } final long localTime = request_time; // add this to the server time to get the local time final long localOffset = (localTime - serverTime); if (Math.abs(localOffset) > 30 * 60 * 1000) { Log.w(TAG, "local clock is off by " + localOffset + "ms"); } if (Thread.interrupted()) { throw new InterruptedException(); } final HttpEntity ent = hr.getEntity(); String selection; String selectionInverse; String[] selectionArgs; if (isDir) { final JSONArray ja = new JSONArray(StreamUtils.inputStreamToString(ent.getContent())); ent.consumeContent(); final int len = ja.length(); selectionArgs = new String[len]; // build the query to see which items are already in the // database final StringBuilder sb = new StringBuilder(); sb.append("("); for (int i = 0; i < len; i++) { if (Thread.interrupted()) { throw new InterruptedException(); } final SyncStatus syncStatus = loadItemFromJsonObject(ja.getJSONObject(i), syncMap, serverTime); syncStatuses.put(syncStatus.remote, syncStatus); selectionArgs[i] = syncStatus.remote; // add in a placeholder for the query sb.append('?'); if (i != (len - 1)) { sb.append(','); } } sb.append(")"); final String placeholders = sb.toString(); selection = JsonSyncableItem._PUBLIC_URI + " IN " + placeholders; selectionInverse = JsonSyncableItem._PUBLIC_URI + " NOT IN " + placeholders; } else { final JSONObject jo = new JSONObject(StreamUtils.inputStreamToString(ent.getContent())); ent.consumeContent(); final SyncStatus syncStatus = loadItemFromJsonObject(jo, syncMap, serverTime); syncStatuses.put(syncStatus.remote, syncStatus); selection = JsonSyncableItem._PUBLIC_URI + "=?"; selectionInverse = JsonSyncableItem._PUBLIC_URI + "!=?"; selectionArgs = new String[] { syncStatus.remote }; } // first check without the querystring. This will ensure that we // properly mark things that we already have in the database. final Cursor check = provider.query(toSyncWithoutQuerystring, SYNC_PROJECTION, selection, selectionArgs, null); // these items are on both sides try { final int pubUriCol = check.getColumnIndex(JsonSyncableItem._PUBLIC_URI); final int idCol = check.getColumnIndex(JsonSyncableItem._ID); // All the items in this cursor should be found on both // the client and the server. for (check.moveToFirst(); !check.isAfterLast(); check.moveToNext()) { if (Thread.interrupted()) { throw new InterruptedException(); } final long id = check.getLong(idCol); final Uri localUri = ContentUris.withAppendedId(toSync, id); final String pubUri = check.getString(pubUriCol); final SyncStatus itemStatus = syncStatuses.get(pubUri); itemStatus.state = SyncState.BOTH_UNKNOWN; itemStatus.local = localUri; // make the status searchable by both remote and // local uri syncStatuses.put(localUri.toString(), itemStatus); } } finally { check.close(); } Cursor c = provider.query(toSync, SYNC_PROJECTION, selection, selectionArgs, null); // these items are on both sides try { final int pubUriCol = c.getColumnIndex(JsonSyncableItem._PUBLIC_URI); final int localModifiedCol = c.getColumnIndex(JsonSyncableItem._MODIFIED_DATE); final int serverModifiedCol = c.getColumnIndex(JsonSyncableItem._SERVER_MODIFIED_DATE); final int idCol = c.getColumnIndex(JsonSyncableItem._ID); // All the items in this cursor should be found on both // the client and the server. for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext()) { if (Thread.interrupted()) { throw new InterruptedException(); } final long id = c.getLong(idCol); final Uri localUri = ContentUris.withAppendedId(toSync, id); final String pubUri = c.getString(pubUriCol); final SyncStatus itemStatus = syncStatuses.get(pubUri); if (itemStatus.state == SyncState.ALREADY_UP_TO_DATE || itemStatus.state == SyncState.NOW_UP_TO_DATE) { if (DEBUG) { Log.d(TAG, localUri + "(" + pubUri + ")" + " is already up to date."); } continue; } itemStatus.local = localUri; // make the status searchable by both remote and local uri syncStatuses.put(localUri.toString(), itemStatus); // last modified as stored in the DB, in phone time final long itemLocalModified = c.getLong(localModifiedCol); // last modified as stored in the DB, in server time final long itemServerModified = c.getLong(serverModifiedCol); final long localAge = localTime - itemLocalModified; final long remoteAge = serverTime - itemStatus.remoteModifiedTime; final long ageDifference = Math.abs(localAge - remoteAge); // up to date, as far remote -> local goes if (itemServerModified == itemStatus.remoteModifiedTime) { itemStatus.state = SyncState.ALREADY_UP_TO_DATE; if (DEBUG) { Log.d(TAG, pubUri + " is up to date."); } // need to download } else if (localAge > remoteAge) { if (DEBUG) { final long serverModified = itemStatus.remoteModifiedTime; Log.d(TAG, pubUri + " : local is " + ageDifference + "ms older (" + android.text.format.DateUtils.formatDateTime(mContext, itemLocalModified, FORMAT_ARGS_DEBUG) + ") than remote (" + android.text.format.DateUtils.formatDateTime(mContext, serverModified, FORMAT_ARGS_DEBUG) + "); updating local copy..."); } itemStatus.state = SyncState.REMOTE_DIRTY; final ContentProviderOperation.Builder b = ContentProviderOperation.newUpdate(localUri); // update this so it's in the local timescale correctServerOffset(itemStatus.remoteCVs, JsonSyncableItem._CREATED_DATE, JsonSyncableItem._CREATED_DATE, localOffset); correctServerOffset(itemStatus.remoteCVs, JsonSyncableItem._SERVER_MODIFIED_DATE, JsonSyncableItem._MODIFIED_DATE, localOffset); b.withValues(itemStatus.remoteCVs); b.withExpectedCount(1); cpo.add(b.build()); cpoPubUris.add(pubUri); syncResult.stats.numUpdates++; // need to upload } else if (localAge < remoteAge) { if (DEBUG) { final long serverModified = itemStatus.remoteModifiedTime; Log.d(TAG, pubUri + " : local is " + ageDifference + "ms newer (" + android.text.format.DateUtils.formatDateTime(mContext, itemLocalModified, FORMAT_ARGS_DEBUG) + ") than remote (" + android.text.format.DateUtils.formatDateTime(mContext, serverModified, FORMAT_ARGS_DEBUG) + "); publishing to server..."); } itemStatus.state = SyncState.LOCAL_DIRTY; mNetworkClient.putJson(pubPath, JsonSyncableItem.toJSON(mContext, localUri, c, syncMap)); } mLastUpdated.markUpdated(localUri); syncResult.stats.numEntries++; } // end for } finally { c.close(); } /* * Apply updates in bulk */ if (cpo.size() > 0) { if (DEBUG) { Log.d(TAG, "applying " + cpo.size() + " bulk updates..."); } final ContentProviderResult[] r = provider.applyBatch(cpo); if (DEBUG) { Log.d(TAG, "Done applying updates. Running postSync handler..."); } for (int i = 0; i < r.length; i++) { final ContentProviderResult res = r[i]; final SyncStatus ss = syncStatuses.get(cpoPubUris.get(i)); if (ss == null) { Log.e(TAG, "can't get sync status for " + res.uri); continue; } syncMap.onPostSyncItem(mContext, account, ss.local, ss.remoteJson, res.count != null ? res.count == 1 : true); ss.state = SyncState.NOW_UP_TO_DATE; } if (DEBUG) { Log.d(TAG, "done running postSync handler."); } cpo.clear(); cpoPubUris.clear(); } if (Thread.interrupted()) { throw new InterruptedException(); } /* * Look through the SyncState.state values and find ones that need to be stored. */ for (final Map.Entry<String, SyncStatus> entry : syncStatuses.entrySet()) { if (Thread.interrupted()) { throw new InterruptedException(); } final String pubUri = entry.getKey(); final SyncStatus status = entry.getValue(); if (status.state == SyncState.REMOTE_ONLY) { if (DEBUG) { Log.d(TAG, pubUri + " is not yet stored locally, adding..."); } // update this so it's in the local timescale correctServerOffset(status.remoteCVs, JsonSyncableItem._CREATED_DATE, JsonSyncableItem._CREATED_DATE, localOffset); correctServerOffset(status.remoteCVs, JsonSyncableItem._SERVER_MODIFIED_DATE, JsonSyncableItem._MODIFIED_DATE, localOffset); final ContentProviderOperation.Builder b = ContentProviderOperation.newInsert(toSync); b.withValues(status.remoteCVs); cpo.add(b.build()); cpoPubUris.add(pubUri); syncResult.stats.numInserts++; } } /* * Execute the content provider operations in bulk. */ if (cpo.size() > 0) { if (DEBUG) { Log.d(TAG, "bulk inserting " + cpo.size() + " items..."); } final ContentProviderResult[] r = provider.applyBatch(cpo); if (DEBUG) { Log.d(TAG, "applyBatch completed. Processing results..."); } int successful = 0; for (int i = 0; i < r.length; i++) { final ContentProviderResult res = r[i]; if (res.uri == null) { syncResult.stats.numSkippedEntries++; Log.e(TAG, "result from content provider bulk operation returned null"); continue; } final String pubUri = cpoPubUris.get(i); final SyncStatus ss = syncStatuses.get(pubUri); if (ss == null) { syncResult.stats.numSkippedEntries++; Log.e(TAG, "could not find sync status for " + cpoPubUris.get(i)); continue; } ss.local = res.uri; if (DEBUG) { Log.d(TAG, "onPostSyncItem(" + res.uri + ", ...); pubUri: " + pubUri); } syncMap.onPostSyncItem(mContext, account, res.uri, ss.remoteJson, res.count != null ? res.count == 1 : true); ss.state = SyncState.NOW_UP_TO_DATE; successful++; } if (DEBUG) { Log.d(TAG, successful + " batch inserts successfully applied."); } } else { if (DEBUG) { Log.d(TAG, "no updates to perform."); } } /** * Look through all the items that we didn't already find on the server side, but which * still have a public uri. They should be checked to make sure they're not deleted. */ c = provider.query(toSync, SYNC_PROJECTION, ProviderUtils.addExtraWhere(selectionInverse, JsonSyncableItem._PUBLIC_URI + " NOT NULL"), selectionArgs, null); try { final int idCol = c.getColumnIndex(JsonSyncableItem._ID); final int pubUriCol = c.getColumnIndex(JsonSyncableItem._PUBLIC_URI); cpo.clear(); for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext()) { final String pubUri = c.getString(pubUriCol); SyncStatus ss = syncStatuses.get(pubUri); final Uri item = isDir ? ContentUris.withAppendedId(toSyncWithoutQuerystring, c.getLong(idCol)) : toSync; if (ss == null) { ss = syncStatuses.get(item.toString()); } if (DEBUG) { Log.d(TAG, item + " was not found in the main list of items on the server (" + pubPath + "), but appears to be a child of " + toSync); if (ss != null) { Log.d(TAG, "found sync status for " + item + ": " + ss); } } if (ss != null) { switch (ss.state) { case ALREADY_UP_TO_DATE: case NOW_UP_TO_DATE: if (DEBUG) { Log.d(TAG, item + " is already up to date. No need to see if it was deleted."); } continue; case BOTH_UNKNOWN: if (DEBUG) { Log.d(TAG, item + " was found on both sides, but has an unknown sync status. Skipping..."); } continue; default: Log.w(TAG, "got an unexpected state for " + item + ": " + ss); } } else { ss = new SyncStatus(pubUri, SyncState.LOCAL_ONLY); ss.local = item; hr = mNetworkClient.head(pubUri); switch (hr.getStatusLine().getStatusCode()) { case 200: if (DEBUG) { Log.d(TAG, "HEAD " + pubUri + " returned 200"); } ss.state = SyncState.BOTH_UNKNOWN; break; case 404: if (DEBUG) { Log.d(TAG, "HEAD " + pubUri + " returned 404. Deleting locally..."); } ss.state = SyncState.DELETED_REMOTELY; final ContentProviderOperation deleteOp = ContentProviderOperation .newDelete(ContentUris.withAppendedId(toSyncWithoutQuerystring, c.getLong(idCol))) .build(); cpo.add(deleteOp); break; default: syncResult.stats.numIoExceptions++; Log.w(TAG, "HEAD " + pubUri + " got unhandled result: " + hr.getStatusLine()); } } syncStatuses.put(pubUri, ss); } // for cursor if (cpo.size() > 0) { final ContentProviderResult[] results = provider.applyBatch(cpo); for (final ContentProviderResult result : results) { if (result.count != 1) { throw new SyncException("Error deleting item"); } } } } finally { c.close(); } syncStatuses.clear(); mLastUpdated.markUpdated(toSync); return true; }
From source file:edu.ku.brc.specify.tasks.subpane.qb.QueryBldrPane.java
/** * @param rootTable/*from w ww . ja va 2 s. c om*/ * @param distinct * @param qfps * @param tblTree * @param keysToRetrieve * @return HQLSpecs for the current fields and settings. */ public static HQLSpecs buildHQL(final TableQRI rootTable, final boolean distinct, final Vector<QueryFieldPanel> qfps, final TableTree tblTree, final RecordSetIFace keysToRetrieve, final boolean searchSynonymy, final boolean isSchemaExport, final Timestamp lastExportTime, final boolean disjunct) throws ParseException { if (qfps.size() == 0) return null; if (keysToRetrieve != null && keysToRetrieve.getNumItems() == 0) return null; StringBuilder fieldsStr = new StringBuilder(); Vector<BaseQRI> list = new Vector<BaseQRI>(); StringBuilder criteriaStr = new StringBuilder(); StringBuilder orderStr = new StringBuilder(); LinkedList<SortElement> sortElements = new LinkedList<SortElement>(); boolean postSortPresent = false; boolean debug = false; ProcessNode root = new ProcessNode(); int fldPosition = distinct ? 0 : 1; for (QueryFieldPanel qfi : qfps) { if (qfi.getFieldQRI() == null) { continue; } qfi.updateQueryField(); if (qfi.isForDisplay()) { fldPosition++; } if (debug) { log.debug("\nNode: " + qfi.getFieldName()); } SortElement orderSpec = qfi.getOrderSpec(distinct ? fldPosition - 1 : fldPosition - 2); if (orderSpec != null) { boolean isPostSortSpec = qfi.getFieldQRI() instanceof TreeLevelQRI || qfi.getFieldQRI() instanceof RelQRI; //dis regard post sorts that may have been saved before //fix for bug #9407 if (!isSchemaExport) { postSortPresent |= isPostSortSpec; } if (!isPostSortSpec || !isSchemaExport) { sortElements.add(orderSpec); } } // Create a Stack (list) of parent from // the current node up to the top // basically we are creating a path of nodes // to determine if we need to create a new node in the tree list.clear(); FieldQRI pqri = qfi.getFieldQRI(); TableTree parent = pqri.getTableTree(); if (qfi.isForDisplay() || qfi.hasCriteria() || orderSpec != null || pqri instanceof RelQRI) { boolean addToList = true; if (pqri instanceof RelQRI) { RelQRI relQRI = (RelQRI) pqri; RelationshipType relType = relQRI.getRelationshipInfo().getType(); // XXX Formatter.getSingleField() checks for ZeroOrOne and // OneToOne rels. if (!relType.equals(RelationshipType.ManyToOne) && !relType.equals(RelationshipType.ManyToMany)/* * treat * manytomany * as * onetomany */) // Maybe // need // to // consider // some // types // of // OneToOne // also????????? { parent = parent.getParent(); if (isSchemaExport && lastExportTime != null) { addToList = true; } else { // parent will initially point to the related table // and don't need to add related table unless it has // children displayed/queried, addToList = false; } } else { DataObjDataFieldFormatIFace formatter = relQRI.getDataObjFormatter(qfi.getFormatName()); if (formatter != null) { boolean isSingleSimpleFormat = formatter.getSingleField() != null && formatter.getFields()[0].getSep() == null; addToList = isSingleSimpleFormat || (isSchemaExport && lastExportTime != null); } else { addToList = false; } } } if (addToList) { list.insertElementAt(pqri, 0); } while (parent != tblTree) { list.insertElementAt(parent.getTableQRI(), 0); parent = parent.getParent(); } if (debug) { log.debug("Path From Top Down:"); for (BaseQRI qri : list) { log.debug(" " + qri.getTitle()); } } // Now walk the stack top (the top most parent) // down and if the path form the top down doesn't // exist then add a new node ProcessNode parentNode = root; int q = 0; for (BaseQRI qri : list) { if (debug) { log.debug("ProcessNode[" + qri.getTitle() + "]"); } q++; if (!parentNode.contains(qri) && (qri instanceof TableQRI || q == list.size())) { ProcessNode newNode = new ProcessNode(qri); parentNode.getKids().add(newNode); if (debug) { log.debug("Adding new node[" + newNode.getQri().getTitle() + "] to Node[" + (parentNode.getQri() == null ? "root" : parentNode.getQri().getTitle()) + "]"); } parentNode = newNode; } else { for (ProcessNode kidNode : parentNode.getKids()) { if (kidNode.getQri().equals(qri)) { parentNode = kidNode; break; } } } } if (debug) { log.debug("Current Tree:"); printTree(root, 0); } } } if (debug) { printTree(root, 0); } StringBuilder fromStr = new StringBuilder(); TableAbbreviator tableAbbreviator = new TableAbbreviator(); List<Pair<DBTableInfo, String>> fromTbls = new LinkedList<Pair<DBTableInfo, String>>(); boolean hqlHasSynJoins = processTree(root, fromStr, fromTbls, 0, tableAbbreviator, tblTree, qfps, searchSynonymy, isSchemaExport, lastExportTime); StringBuilder sqlStr = new StringBuilder(); sqlStr.append("select "); //if (distinct /*|| hqlHasSynJoins*/) { sqlStr.append("distinct "); } if (!distinct) { fieldsStr.append(tableAbbreviator.getAbbreviation(rootTable.getTableTree())); fieldsStr.append("."); fieldsStr.append(rootTable.getTableInfo().getIdFieldName()); } List<Pair<String, Object>> paramsToSet = new LinkedList<Pair<String, Object>>(); boolean visibleFldExists = false; for (QueryFieldPanel qfi : qfps) { if (qfi.getFieldQRI() == null) { continue; } if (qfi.isForDisplay()) { visibleFldExists = true; String fldSpec = qfi.getFieldQRI().getSQLFldSpec(tableAbbreviator, false, isSchemaExport, qfi.getFormatName()); if (StringUtils.isNotEmpty(fldSpec)) { if (fieldsStr.length() > 0) { fieldsStr.append(", "); } fieldsStr.append(fldSpec); } } if (keysToRetrieve == null || qfi.isEnforced()) { String criteria = qfi.getCriteriaFormula(tableAbbreviator, paramsToSet); boolean isDisplayOnly = StringUtils.isEmpty(criteria); if (!isDisplayOnly) { if (criteria.equals("2+2=2") && qfi.isNegated()) { criteria = ""; } if (criteria.length() > 0 && hqlHasSynJoins && isSynSearchable(qfi.getFieldQRI()) && !qfi.isEmptyCriterion()) { criteria = adjustForSynSearch( tableAbbreviator.getAbbreviation(qfi.getFieldQRI().getTable().getTableTree()), criteria, qfi.isNegated()); } if (!isDisplayOnly && criteriaStr.length() > 0 && criteria.length() > 0) { criteriaStr.append(disjunct ? " OR " : " AND "); } criteriaStr.append(criteria); } } } if (!visibleFldExists) { throw new ParseException(getResourceString("QueryBldrPane.NoVisibleColumns"), -1); } sqlStr.append(fieldsStr); sqlStr.append(" from "); sqlStr.append(fromStr); if (keysToRetrieve != null) { if (!StringUtils.isEmpty(criteriaStr.toString())) { criteriaStr.append(" and "); } criteriaStr.append("("); criteriaStr.append(tableAbbreviator.getAbbreviation(rootTable.getTableTree()) + "." + rootTable.getTableInfo().getIdFieldName() + " in("); boolean comma = false; int maxInClauseLen = 2500; int inClauseLen = 0; for (RecordSetItemIFace item : keysToRetrieve.getOrderedItems()) { if (inClauseLen == maxInClauseLen) { criteriaStr.append(") or "); criteriaStr.append(tableAbbreviator.getAbbreviation(rootTable.getTableTree()) + "." + rootTable.getTableInfo().getIdFieldName() + " in("); inClauseLen = 0; } else if (comma) { criteriaStr.append(","); } else { comma = true; } criteriaStr.append(item.getRecordId()); inClauseLen++; } criteriaStr.append("))"); } else { //Assuming that this not necessary when keysToRetrieve is non-null because //the keys will already been filtered properly. (???) // Add extra where's for system fields for root table only, see notes below at end of for block boolean isRootTbl = true; for (Pair<DBTableInfo, String> fromTbl : fromTbls) { String specialColumnWhere = null; if (fromTbl.getFirst().getTableId() == Attachment.getClassTableId()) { String prefix = fromTbl.getSecond() + "."; specialColumnWhere = "((" + prefix + "scopeType = 0 and " + prefix + "scopeID = " + AppContextMgr.getInstance() .getClassObject(edu.ku.brc.specify.datamodel.Collection.class).getCollectionId() + ") or" + "(" + prefix + "scopeType = 1 and " + prefix + "scopeID = " + AppContextMgr.getInstance().getClassObject(Discipline.class).getDisciplineId() + ") or" + "(" + prefix + "scopeType = 2 and " + prefix + "scopeID = " + AppContextMgr.getInstance().getClassObject(Division.class).getDivisionId() + ") or" + "(" + prefix + "scopeType = 3 and " + prefix + "scopeID = " + AppContextMgr.getInstance().getClassObject(Institution.class).getInstitutionId() + "))"; } else { specialColumnWhere = QueryAdjusterForDomain.getInstance().getSpecialColumns(fromTbl.getFirst(), true, !isRootTbl && true/* XXX should only use left join when necessary */, fromTbl.getSecond()); } isRootTbl = false; if (StringUtils.isNotEmpty(specialColumnWhere)) { if (criteriaStr.length() > 0) { criteriaStr.append(" AND "); } criteriaStr.append(specialColumnWhere); } //Actually, assuming data is valid, it should only be necessary to add the Adjustments for the root table? //XXX if this works, fix this loop. Also, join parameter code in getSpecialColumns will probably be irrelevant. break; } //...done adding system whereses //get only records modified/added since last export of the schema... if (isSchemaExport && lastExportTime != null) { if (criteriaStr.length() > 0) { criteriaStr.append(" AND ("); } String timestampParam = "spparam" + paramsToSet.size(); paramsToSet.add(new Pair<String, Object>(timestampParam, lastExportTime)); criteriaStr.append(getTimestampWhere(fromTbls, timestampParam, lastExportTime)); criteriaStr.append(") "); } } if (criteriaStr.length() > 0) { sqlStr.append(" where "); sqlStr.append(criteriaStr); } if (sortElements.size() > 0 && !postSortPresent) { for (SortElement se : sortElements) { if (!StringUtils.isEmpty(orderStr.toString())) { orderStr.append(", "); } orderStr.append(distinct ? se.getColumn() + 1 : se.getColumn() + 2); if (se.getDirection() == SortElement.DESCENDING) { orderStr.append(" DESC"); } } sortElements.clear(); } if (orderStr.length() > 0) { sqlStr.append(" order by "); sqlStr.append(orderStr); } if (debug) { log.debug(sqlStr.toString()); log.debug("sort:"); for (SortElement s : sortElements) { log.debug(" " + s.getColumn() + " - " + s.getDirection()); } } String result = sqlStr.toString(); if (!checkHQL(result)) return null; log.info(result); return new HQLSpecs(result, paramsToSet, sortElements, hqlHasSynJoins); }