parent
93db8c4c0e
commit
4cb48a38a9
16 changed files with 28 additions and 2200 deletions
|
@ -56,55 +56,6 @@ public class NetworkUtils {
|
|||
return e.getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
public static String sendPostDataRequest(String urlText, InputStream data){
|
||||
try {
|
||||
log.info("POST : " + urlText);
|
||||
HttpURLConnection conn = getHttpURLConnection(urlText);
|
||||
conn.setDoInput(true);
|
||||
conn.setDoOutput(false);
|
||||
conn.setRequestMethod("POST");
|
||||
conn.setRequestProperty("Accept","*/*");
|
||||
conn.setRequestProperty("User-Agent", "OsmAnd"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
|
||||
OutputStream ous = conn.getOutputStream();
|
||||
ous.write(("--" + BOUNDARY + "\r\n").getBytes());
|
||||
ous.write(("content-disposition: form-data; name=\"" + "file" + "\"; filename=\"" + "image1" + "\"\r\n").getBytes()); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
ous.write(("Content-Type: application/octet-stream\r\n\r\n").getBytes()); //$NON-NLS-1$
|
||||
Algorithms.streamCopy(data,ous);
|
||||
ous.write(("\r\n--" + BOUNDARY + "--\r\n").getBytes()); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
ous.flush();
|
||||
log.info("Response code and message : " + conn.getResponseCode() + " " + conn.getResponseMessage());
|
||||
if(conn.getResponseCode() != 200){
|
||||
return conn.getResponseMessage();
|
||||
}
|
||||
StringBuilder responseBody = new StringBuilder();
|
||||
InputStream is = conn.getInputStream();
|
||||
responseBody.setLength(0);
|
||||
if (is != null) {
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(is, "UTF-8")); //$NON-NLS-1$
|
||||
String s;
|
||||
boolean first = true;
|
||||
while ((s = in.readLine()) != null) {
|
||||
if(first){
|
||||
first = false;
|
||||
} else {
|
||||
responseBody.append("\n"); //$NON-NLS-1$
|
||||
}
|
||||
responseBody.append(s);
|
||||
}
|
||||
is.close();
|
||||
}
|
||||
Algorithms.closeStream(is);
|
||||
Algorithms.closeStream(data);
|
||||
Algorithms.closeStream(ous);
|
||||
return responseBody.toString();
|
||||
} catch (IOException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return e.getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
private static final String BOUNDARY = "CowMooCowMooCowCowCow"; //$NON-NLS-1$
|
||||
public static String uploadFile(String urlText, File fileToUpload, String userNamePassword,
|
||||
OsmOAuthAuthorizationClient client,
|
||||
|
|
Binary file not shown.
|
@ -34,20 +34,17 @@ import androidx.core.content.ContextCompat;
|
|||
import androidx.core.graphics.drawable.DrawableCompat;
|
||||
|
||||
import net.osmand.AndroidUtils;
|
||||
import net.osmand.PlatformUtil;
|
||||
import net.osmand.binary.BinaryMapIndexReader;
|
||||
import net.osmand.data.Amenity;
|
||||
import net.osmand.data.LatLon;
|
||||
import net.osmand.data.PointDescription;
|
||||
import net.osmand.data.QuadRect;
|
||||
import net.osmand.osm.PoiCategory;
|
||||
import net.osmand.osm.io.NetworkUtils;
|
||||
import net.osmand.plus.OsmAndFormatter;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.OsmandPlugin;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.UiUtilities;
|
||||
import net.osmand.plus.activities.ActivityResultListener;
|
||||
import net.osmand.plus.activities.MapActivity;
|
||||
import net.osmand.plus.helpers.FontCache;
|
||||
import net.osmand.plus.mapcontextmenu.builders.cards.AbstractCard;
|
||||
|
@ -56,7 +53,6 @@ import net.osmand.plus.mapcontextmenu.builders.cards.ImageCard;
|
|||
import net.osmand.plus.mapcontextmenu.builders.cards.ImageCard.GetImageCardsTask;
|
||||
import net.osmand.plus.mapcontextmenu.builders.cards.NoImagesCard;
|
||||
import net.osmand.plus.mapcontextmenu.controllers.TransportStopController;
|
||||
import net.osmand.plus.osmedit.utils.SecUtils;
|
||||
import net.osmand.plus.poi.PoiUIFilter;
|
||||
import net.osmand.plus.render.RenderingIcons;
|
||||
import net.osmand.plus.transport.TransportStopRoute;
|
||||
|
@ -66,9 +62,7 @@ import net.osmand.plus.widgets.TextViewEx;
|
|||
import net.osmand.plus.widgets.tools.ClickableSpanTouchListener;
|
||||
import net.osmand.util.Algorithms;
|
||||
import net.osmand.util.MapUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
|
@ -83,7 +77,7 @@ public class MenuBuilder {
|
|||
|
||||
public static final float SHADOW_HEIGHT_TOP_DP = 17f;
|
||||
public static final int TITLE_LIMIT = 60;
|
||||
protected static final String[] arrowChars = new String[] {"=>", " - "};
|
||||
protected static final String[] arrowChars = new String[]{"=>"," - "};
|
||||
|
||||
protected MapActivity mapActivity;
|
||||
protected MapContextMenu mapContextMenu;
|
||||
|
@ -109,8 +103,6 @@ public class MenuBuilder {
|
|||
private String preferredMapLang;
|
||||
private String preferredMapAppLang;
|
||||
private boolean transliterateNames;
|
||||
private static final int PICK_IMAGE = 1231;
|
||||
private static final Log LOG = PlatformUtil.getLog(MenuBuilder.class);
|
||||
|
||||
public interface CollapseExpandListener {
|
||||
void onCollapseExpand(boolean collapsed);
|
||||
|
@ -220,59 +212,10 @@ public class MenuBuilder {
|
|||
if (showOnlinePhotos) {
|
||||
buildNearestPhotosRow(view);
|
||||
}
|
||||
buildUploadImagesRow(view);
|
||||
buildPluginRows(view);
|
||||
// buildAfter(view);
|
||||
}
|
||||
|
||||
public void buildUploadImagesRow(View view) {
|
||||
if (mapContextMenu != null) {
|
||||
//TODO to strings
|
||||
String title = "Upload images";
|
||||
buildRow(view, R.drawable.ic_action_note_dark, null, title, 0, false,
|
||||
null, false, 0, false, new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
mapActivity.registerActivityResultListener(new ActivityResultListener(PICK_IMAGE,
|
||||
new ActivityResultListener.OnActivityResultListener() {
|
||||
@Override
|
||||
public void onResult(int resultCode, Intent resultData) {
|
||||
InputStream inputStream = null;
|
||||
try {
|
||||
inputStream = mapActivity.getContentResolver().openInputStream(resultData.getData());
|
||||
} catch (FileNotFoundException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
handleSelectedImage(inputStream);
|
||||
}
|
||||
}));
|
||||
Intent intent = new Intent();
|
||||
intent.setType("image/*");
|
||||
intent.setAction(Intent.ACTION_GET_CONTENT);
|
||||
mapActivity.startActivityForResult(Intent.createChooser(intent, "Select Picture"), PICK_IMAGE);
|
||||
}
|
||||
}, false);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleSelectedImage(final InputStream image) {
|
||||
Thread t = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try{
|
||||
String url = "https://test.openplacereviews.org/api/ipfs/image";
|
||||
String response = NetworkUtils.sendPostDataRequest(url, image);
|
||||
//TODO
|
||||
(new SecUtils()).main(new String[0]);
|
||||
}
|
||||
catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
t.start();
|
||||
}
|
||||
|
||||
private boolean showTransportRoutes() {
|
||||
return showLocalTransportRoutes() || showNearbyTransportRoutes();
|
||||
}
|
||||
|
@ -311,7 +254,7 @@ public class MenuBuilder {
|
|||
protected boolean needBuildPlainMenuItems() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
protected boolean needBuildCoordinatesRow() {
|
||||
return true;
|
||||
}
|
||||
|
@ -339,7 +282,7 @@ public class MenuBuilder {
|
|||
|
||||
protected void buildNearestWikiRow(View view) {
|
||||
if (processNearestWiki() && nearestWiki.size() > 0) {
|
||||
buildRow(view, R.drawable.ic_action_wikipedia, null, app.getString(R.string.wiki_around) + " (" + nearestWiki.size() + ")", 0,
|
||||
buildRow(view, R.drawable.ic_action_wikipedia, null, app.getString(R.string.wiki_around) + " (" + nearestWiki.size()+")", 0,
|
||||
true, getCollapsableWikiView(view.getContext(), true),
|
||||
false, 0, false, null, false);
|
||||
}
|
||||
|
@ -379,9 +322,9 @@ public class MenuBuilder {
|
|||
locationData.remove(PointDescription.LOCATION_LIST_HEADER);
|
||||
CollapsableView cv = getLocationCollapsableView(locationData);
|
||||
buildRow(view, R.drawable.ic_action_get_my_location, null, title, 0, true, cv, false, 1,
|
||||
false, null, false);
|
||||
false, null, false);
|
||||
}
|
||||
|
||||
|
||||
private void startLoadingImages() {
|
||||
if (onlinePhotoCardsRow == null) {
|
||||
return;
|
||||
|
@ -436,7 +379,7 @@ public class MenuBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
protected void buildDescription(View view) {
|
||||
protected void buildDescription(View view){
|
||||
}
|
||||
|
||||
protected void buildAfter(View view) {
|
||||
|
@ -452,8 +395,8 @@ public class MenuBuilder {
|
|||
}
|
||||
|
||||
public View buildRow(View view, int iconId, String buttonText, String text, int textColor,
|
||||
boolean collapsable, final CollapsableView collapsableView,
|
||||
boolean needLinks, int textLinesLimit, boolean isUrl, OnClickListener onClickListener, boolean matchWidthDivider) {
|
||||
boolean collapsable, final CollapsableView collapsableView,
|
||||
boolean needLinks, int textLinesLimit, boolean isUrl, OnClickListener onClickListener, boolean matchWidthDivider) {
|
||||
return buildRow(view, iconId == 0 ? null : getRowIcon(iconId), buttonText, text, textColor, null, collapsable, collapsableView,
|
||||
needLinks, textLinesLimit, isUrl, onClickListener, matchWidthDivider);
|
||||
}
|
||||
|
@ -537,7 +480,7 @@ public class MenuBuilder {
|
|||
textPrefixView.setLayoutParams(llTextParams);
|
||||
textPrefixView.setTypeface(FontCache.getRobotoRegular(view.getContext()));
|
||||
textPrefixView.setTextSize(12);
|
||||
textPrefixView.setTextColor(app.getResources().getColor(light ? R.color.text_color_secondary_light : R.color.text_color_secondary_dark));
|
||||
textPrefixView.setTextColor(app.getResources().getColor(light ? R.color.text_color_secondary_light: R.color.text_color_secondary_dark));
|
||||
textPrefixView.setMinLines(1);
|
||||
textPrefixView.setMaxLines(1);
|
||||
textPrefixView.setText(textPrefix);
|
||||
|
@ -583,7 +526,7 @@ public class MenuBuilder {
|
|||
textViewSecondary.setLayoutParams(llTextSecondaryParams);
|
||||
textViewSecondary.setTypeface(FontCache.getRobotoRegular(view.getContext()));
|
||||
textViewSecondary.setTextSize(14);
|
||||
textViewSecondary.setTextColor(app.getResources().getColor(light ? R.color.text_color_secondary_light : R.color.text_color_secondary_dark));
|
||||
textViewSecondary.setTextColor(app.getResources().getColor(light ? R.color.text_color_secondary_light: R.color.text_color_secondary_dark));
|
||||
textViewSecondary.setText(secondaryText);
|
||||
llText.addView(textViewSecondary);
|
||||
}
|
||||
|
@ -638,7 +581,7 @@ public class MenuBuilder {
|
|||
}
|
||||
if (collapsableView.getContentView().getParent() != null) {
|
||||
((ViewGroup) collapsableView.getContentView().getParent())
|
||||
.removeView(collapsableView.getContentView());
|
||||
.removeView(collapsableView.getContentView());
|
||||
}
|
||||
baseView.addView(collapsableView.getContentView());
|
||||
}
|
||||
|
@ -798,8 +741,8 @@ public class MenuBuilder {
|
|||
}
|
||||
|
||||
public void addPlainMenuItem(int iconId, String text, boolean needLinks, boolean isUrl,
|
||||
boolean collapsable, CollapsableView collapsableView,
|
||||
OnClickListener onClickListener) {
|
||||
boolean collapsable, CollapsableView collapsableView,
|
||||
OnClickListener onClickListener) {
|
||||
plainMenuItems.add(new PlainMenuItem(iconId, null, text, needLinks, isUrl, collapsable, collapsableView, onClickListener));
|
||||
}
|
||||
|
||||
|
@ -1021,7 +964,7 @@ public class MenuBuilder {
|
|||
button.setTypeface(FontCache.getRobotoRegular(context));
|
||||
int bg;
|
||||
if (selected) {
|
||||
bg = light ? R.drawable.context_menu_controller_bg_light_selected : R.drawable.context_menu_controller_bg_dark_selected;
|
||||
bg = light ? R.drawable.context_menu_controller_bg_light_selected: R.drawable.context_menu_controller_bg_dark_selected;
|
||||
} else if (showAll) {
|
||||
bg = light ? R.drawable.context_menu_controller_bg_light_show_all : R.drawable.context_menu_controller_bg_dark_show_all;
|
||||
} else {
|
||||
|
@ -1078,7 +1021,7 @@ public class MenuBuilder {
|
|||
|
||||
private List<Amenity> getAmenities(QuadRect rect, PoiUIFilter wikiPoiFilter) {
|
||||
return wikiPoiFilter.searchAmenities(rect.top, rect.left,
|
||||
rect.bottom, rect.right, -1, null);
|
||||
rect.bottom, rect.right, -1, null);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
|
|
@ -18,7 +18,6 @@ import net.osmand.osm.edit.Entity.EntityType;
|
|||
import net.osmand.osm.edit.EntityInfo;
|
||||
import net.osmand.osm.edit.Node;
|
||||
import net.osmand.osm.edit.Way;
|
||||
import net.osmand.osm.io.Base64;
|
||||
import net.osmand.osm.io.NetworkUtils;
|
||||
import net.osmand.osm.io.OsmBaseStorage;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
|
@ -31,8 +30,10 @@ import org.apache.commons.logging.Log;
|
|||
import org.xmlpull.v1.XmlPullParserException;
|
||||
import org.xmlpull.v1.XmlSerializer;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.net.MalformedURLException;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.HashMap;
|
||||
|
@ -107,16 +108,14 @@ public class OpenstreetmapRemoteUtil implements OpenstreetmapUtil {
|
|||
boolean doAuthenticate) {
|
||||
log.info("Sending request " + url); //$NON-NLS-1$
|
||||
try {
|
||||
OsmOAuthAuthorizationAdapter client = new OsmOAuthAuthorizationAdapter(ctx);
|
||||
if (doAuthenticate) {
|
||||
if (client.isValidToken()) {
|
||||
Response response = client.performRequest(url, requestMethod, requestBody);
|
||||
return response.getBody();
|
||||
} else {
|
||||
return performBasicAuthRequest(url, requestMethod, requestBody, userOperation);
|
||||
}
|
||||
} else {
|
||||
Response response = client.performRequestWithoutAuth(url, requestMethod, requestBody);
|
||||
if (doAuthenticate){
|
||||
OsmOAuthAuthorizationAdapter client = new OsmOAuthAuthorizationAdapter(ctx);
|
||||
Response response = client.performRequest(url,requestMethod,requestBody);
|
||||
return response.getBody();
|
||||
}
|
||||
else {
|
||||
OsmOAuthAuthorizationAdapter client = new OsmOAuthAuthorizationAdapter(ctx);
|
||||
Response response = client.performRequestWithoutAuth(url,requestMethod,requestBody);
|
||||
return response.getBody();
|
||||
}
|
||||
} catch (NullPointerException e) {
|
||||
|
@ -140,64 +139,11 @@ public class OpenstreetmapRemoteUtil implements OpenstreetmapUtil {
|
|||
log.error(userOperation + " " + ctx.getString(R.string.failed_op), e); //$NON-NLS-1$
|
||||
showWarning(MessageFormat.format(ctx.getResources().getString(R.string.shared_string_action_template)
|
||||
+ ": " + ctx.getResources().getString(R.string.shared_string_unexpected_error), userOperation));
|
||||
} catch (Exception e) {
|
||||
log.error(userOperation + " " + ctx.getString(R.string.failed_op), e); //$NON-NLS-1$
|
||||
showWarning(MessageFormat.format(ctx.getResources().getString(R.string.shared_string_action_template)
|
||||
+ ": " + ctx.getResources().getString(R.string.shared_string_unexpected_error), userOperation));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private String performBasicAuthRequest(String url, String requestMethod, String requestBody, String userOperation) throws IOException {
|
||||
HttpURLConnection connection = NetworkUtils.getHttpURLConnection(url);
|
||||
connection.setConnectTimeout(15000);
|
||||
connection.setRequestMethod(requestMethod);
|
||||
connection.setRequestProperty("User-Agent", Version.getFullVersion(ctx)); //$NON-NLS-1$
|
||||
StringBuilder responseBody = new StringBuilder();
|
||||
String token = settings.USER_NAME.get() + ":" + settings.USER_PASSWORD.get(); //$NON-NLS-1$
|
||||
connection.addRequestProperty("Authorization", "Basic " + Base64.encode(token.getBytes("UTF-8"))); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
||||
connection.setDoInput(true);
|
||||
if (requestMethod.equals("PUT") || requestMethod.equals("POST") || requestMethod.equals("DELETE")) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
||||
connection.setDoOutput(true);
|
||||
connection.setRequestProperty("Content-type", "text/xml"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
OutputStream out = connection.getOutputStream();
|
||||
if (requestBody != null) {
|
||||
BufferedWriter bwr = new BufferedWriter(new OutputStreamWriter(out, "UTF-8"), 1024); //$NON-NLS-1$
|
||||
bwr.write(requestBody);
|
||||
bwr.flush();
|
||||
}
|
||||
out.close();
|
||||
}
|
||||
connection.connect();
|
||||
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
|
||||
String msg = userOperation
|
||||
+ " " + ctx.getString(R.string.failed_op) + " : " + connection.getResponseMessage(); //$NON-NLS-1$//$NON-NLS-2$
|
||||
log.error(msg);
|
||||
showWarning(msg);
|
||||
} else {
|
||||
log.info("Response : " + connection.getResponseMessage()); //$NON-NLS-1$
|
||||
// populate return fields.
|
||||
responseBody.setLength(0);
|
||||
InputStream i = connection.getInputStream();
|
||||
if (i != null) {
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(i, "UTF-8"), 256); //$NON-NLS-1$
|
||||
String s;
|
||||
boolean f = true;
|
||||
while ((s = in.readLine()) != null) {
|
||||
if (!f) {
|
||||
responseBody.append("\n"); //$NON-NLS-1$
|
||||
} else {
|
||||
f = false;
|
||||
}
|
||||
responseBody.append(s);
|
||||
}
|
||||
}
|
||||
return responseBody.toString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public long openChangeSet(String comment) {
|
||||
long id = -1;
|
||||
StringWriter writer = new StringWriter(256);
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
package net.osmand.plus.osmedit.utils;
|
||||
|
||||
public class FailedVerificationException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = -4936205097177668159L;
|
||||
|
||||
|
||||
public FailedVerificationException(Exception e) {
|
||||
super(e);
|
||||
}
|
||||
|
||||
|
||||
public FailedVerificationException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
|
@ -1,135 +0,0 @@
|
|||
package net.osmand.plus.osmedit.utils;
|
||||
|
||||
import com.google.gson.*;
|
||||
import net.osmand.plus.osmedit.utils.ops.OpObject;
|
||||
import net.osmand.plus.osmedit.utils.ops.OpOperation;
|
||||
|
||||
import java.io.Reader;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.*;
|
||||
|
||||
public class JsonFormatter {
|
||||
|
||||
private Gson gson;
|
||||
|
||||
private Gson gsonOperationHash;
|
||||
|
||||
private Gson gsonFullOutput;
|
||||
|
||||
public JsonFormatter() {
|
||||
GsonBuilder builder = new GsonBuilder();
|
||||
builder.disableHtmlEscaping();
|
||||
builder.registerTypeAdapter(OpOperation.class, new OpOperation.OpOperationBeanAdapter(false));
|
||||
builder.registerTypeAdapter(OpObject.class, new OpObject.OpObjectAdapter(false));
|
||||
builder.registerTypeAdapter(TreeMap.class, new MapDeserializerDoubleAsIntFix());
|
||||
gson = builder.create();
|
||||
|
||||
builder = new GsonBuilder();
|
||||
builder.disableHtmlEscaping();
|
||||
builder.registerTypeAdapter(OpOperation.class, new OpOperation.OpOperationBeanAdapter(false, true));
|
||||
builder.registerTypeAdapter(OpObject.class, new OpObject.OpObjectAdapter(false));
|
||||
builder.registerTypeAdapter(TreeMap.class, new MapDeserializerDoubleAsIntFix());
|
||||
gsonOperationHash = builder.create();
|
||||
|
||||
builder = new GsonBuilder();
|
||||
builder.disableHtmlEscaping();
|
||||
builder.registerTypeAdapter(OpOperation.class, new OpOperation.OpOperationBeanAdapter(true));
|
||||
builder.registerTypeAdapter(OpObject.class, new OpObject.OpObjectAdapter(true));
|
||||
builder.registerTypeAdapter(TreeMap.class, new MapDeserializerDoubleAsIntFix());
|
||||
gsonFullOutput = builder.create();
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static class MapDeserializerDoubleAsIntFix implements JsonDeserializer<TreeMap<String, Object>> {
|
||||
|
||||
@Override @SuppressWarnings("unchecked")
|
||||
public TreeMap<String, Object> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
|
||||
return (TreeMap<String, Object>) read(json);
|
||||
}
|
||||
|
||||
public Object read(JsonElement in) {
|
||||
|
||||
if(in.isJsonArray()){
|
||||
List<Object> list = new ArrayList<Object>();
|
||||
JsonArray arr = in.getAsJsonArray();
|
||||
for (JsonElement anArr : arr) {
|
||||
list.add(read(anArr));
|
||||
}
|
||||
return list;
|
||||
}else if(in.isJsonObject()){
|
||||
Map<String, Object> map = new TreeMap<String, Object>();
|
||||
JsonObject obj = in.getAsJsonObject();
|
||||
Set<Map.Entry<String, JsonElement>> entitySet = obj.entrySet();
|
||||
for(Map.Entry<String, JsonElement> entry: entitySet){
|
||||
map.put(entry.getKey(), read(entry.getValue()));
|
||||
}
|
||||
return map;
|
||||
}else if(in.isJsonPrimitive()){
|
||||
JsonPrimitive prim = in.getAsJsonPrimitive();
|
||||
if(prim.isBoolean()){
|
||||
return prim.getAsBoolean();
|
||||
}else if(prim.isString()){
|
||||
return prim.getAsString();
|
||||
}else if(prim.isNumber()){
|
||||
Number num = prim.getAsNumber();
|
||||
// here you can handle double int/long values
|
||||
// and return any type you want
|
||||
// this solution will transform 3.0 float to long values
|
||||
if(Math.ceil(num.doubleValue()) == num.longValue() && (!num.toString().contains(".") || num.toString().split("\\.")[1].length() <= 1))
|
||||
return num.longValue();
|
||||
else {
|
||||
return num.doubleValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// operations to parse / format related
|
||||
public OpOperation parseOperation(String opJson) {
|
||||
return gson.fromJson(opJson, OpOperation.class);
|
||||
}
|
||||
|
||||
public OpObject parseObject(String opJson) {
|
||||
return gson.fromJson(opJson, OpObject.class);
|
||||
}
|
||||
|
||||
public Object parseBlock(String opJson) {
|
||||
throw new UnsupportedOperationException("");
|
||||
}
|
||||
|
||||
public JsonElement toJsonElement(Object o) {
|
||||
return gson.toJsonTree(o);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public TreeMap<String, Object> fromJsonToTreeMap(String json) {
|
||||
return gson.fromJson(json, TreeMap.class);
|
||||
}
|
||||
|
||||
|
||||
public <T> T fromJson(Reader json, Class<T> classOfT) throws JsonSyntaxException {
|
||||
return gson.fromJson(json, classOfT);
|
||||
}
|
||||
|
||||
public String fullObjectToJson(Object o) {
|
||||
return gsonFullOutput.toJson(o);
|
||||
}
|
||||
|
||||
|
||||
public String opToJsonNoHash(OpOperation op) {
|
||||
return gsonOperationHash.toJson(op);
|
||||
}
|
||||
|
||||
public String opToJson(OpOperation op) {
|
||||
return gson.toJson(op);
|
||||
}
|
||||
|
||||
public String objToJson(OpObject op) {
|
||||
return gson.toJson(op);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,411 +0,0 @@
|
|||
package net.osmand.plus.osmedit.utils;
|
||||
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.*;
|
||||
import java.security.spec.ECGenParameterSpec;
|
||||
import java.security.spec.EncodedKeySpec;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
//import java.util.Base64;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
import net.osmand.plus.osmedit.utils.ops.OpOperation;
|
||||
import org.apache.commons.codec.DecoderException;
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
//import org.bouncycastle.crypto.generators.SCrypt;
|
||||
//import org.bouncycastle.crypto.prng.FixedSecureRandom;
|
||||
public class SecUtils {
|
||||
private static final String SIG_ALGO_SHA1_EC = "SHA1withECDSA";
|
||||
private static final String SIG_ALGO_NONE_EC = "NonewithECDSA";
|
||||
|
||||
public static final String SIG_ALGO_ECDSA = "ECDSA";
|
||||
public static final String ALGO_EC = "EC";
|
||||
public static final String EC_256SPEC_K1 = "secp256k1";
|
||||
|
||||
public static final String KEYGEN_PWD_METHOD_1 = "EC256K1_S17R8";
|
||||
public static final String DECODE_BASE64 = "base64";
|
||||
public static final String HASH_SHA256 = "sha256";
|
||||
public static final String HASH_SHA1 = "sha1";
|
||||
|
||||
public static final String JSON_MSG_TYPE = "json";
|
||||
public static final String KEY_BASE64 = DECODE_BASE64;
|
||||
|
||||
public static void main(String[] args) {
|
||||
//1) create op, 2) sign op 3) send to server process op
|
||||
//
|
||||
KeyPairGenerator keyGen = null ;
|
||||
SecureRandom random = null;
|
||||
try {
|
||||
keyGen = KeyPairGenerator.getInstance(ALGO_EC);
|
||||
random = SecureRandom.getInstance("SHA1PRNG");
|
||||
keyGen.initialize(1024, random);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
KeyPair kp = null;
|
||||
try {
|
||||
kp = SecUtils.getKeyPair(ALGO_EC,
|
||||
"base64:PKCS#8:MD4CAQAwEAYHKoZIzj0CAQYFK4EEAAoEJzAlAgEBBCDR+/ByIjTHZgfdnMfP9Ab5s14mMzFX+8DYqUiGmf/3rw=="
|
||||
, "base64:X.509:MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEOMUiRZwU7wW8L3A1qaJPwhAZy250VaSxJmKCiWdn9EMeubXQgWNT8XUWLV5Nvg7O3sD+1AAQLG5kHY8nOc/AyA==");
|
||||
} catch (FailedVerificationException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
// KeyPair kp = generateECKeyPairFromPassword(KEYGEN_PWD_METHOD_1, "openplacereviews", "");
|
||||
// KeyPair kp = generateRandomEC256K1KeyPair();
|
||||
System.out.println(kp.getPrivate().getFormat());
|
||||
System.out.println(kp.getPrivate().getAlgorithm());
|
||||
try {
|
||||
System.out.println(SecUtils.validateKeyPair(ALGO_EC, kp.getPrivate(), kp.getPublic()));
|
||||
} catch (FailedVerificationException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
String pr = encodeKey(KEY_BASE64, kp.getPrivate());
|
||||
String pk = encodeKey(KEY_BASE64, kp.getPublic());
|
||||
String algo = kp.getPrivate().getAlgorithm();
|
||||
System.out.println(String.format("Private key: %s %s\nPublic key: %s %s", kp.getPrivate().getFormat(), pr, kp
|
||||
.getPublic().getFormat(), pk));
|
||||
String signMessageTest = "Hello this is a registration message test";
|
||||
byte[] signature = signMessageWithKey(kp, signMessageTest.getBytes(), SIG_ALGO_SHA1_EC);
|
||||
System.out.println(String.format("Signed message: %s %s", android.util.Base64.decode(signature, android.util.Base64.DEFAULT),
|
||||
signMessageTest));
|
||||
|
||||
KeyPair nk = null;
|
||||
try {
|
||||
nk = getKeyPair(algo, pr, pk);
|
||||
} catch (FailedVerificationException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
// validate
|
||||
pr = new String(android.util.Base64.decode(nk.getPrivate().getEncoded(), android.util.Base64.DEFAULT));
|
||||
pk = new String(android.util.Base64.decode(nk.getPublic().getEncoded(), android.util.Base64.DEFAULT));
|
||||
|
||||
System.out.println(String.format("Private key: %s %s\nPublic key: %s %s", nk.getPrivate().getFormat(), pr, nk
|
||||
.getPublic().getFormat(), pk));
|
||||
System.out.println(validateSignature(nk, signMessageTest.getBytes(), SIG_ALGO_SHA1_EC, signature));
|
||||
|
||||
JsonFormatter formatter = new JsonFormatter();
|
||||
String msg = "{\n" +
|
||||
" \"type\" : \"sys.signup\",\n" +
|
||||
" \"signed_by\": \"openplacereviews\",\n" +
|
||||
" \"create\": [{\n" +
|
||||
" \"id\": [\"openplacereviews\"],\n" +
|
||||
" \"name\" : \"openplacereviews\",\n" +
|
||||
" \"algo\": \"EC\",\n" +
|
||||
" \"auth_method\": \"provided\",\n" +
|
||||
" \"pubkey\": \"base64:X.509:MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEn6GkOTN3SYc+OyCYCpqPzKPALvUgfUVNDJ+6eyBlCHI1/gKcVqzHLwaO90ksb29RYBiF4fW/PqHcECNzwJB+QA==\"\n" +
|
||||
" }]\n" +
|
||||
" }";
|
||||
|
||||
OpOperation opOperation = formatter.parseOperation(msg);
|
||||
String hash = JSON_MSG_TYPE + ":"
|
||||
+ SecUtils.calculateHashWithAlgo(SecUtils.HASH_SHA256, null,
|
||||
formatter.opToJsonNoHash(opOperation));
|
||||
|
||||
byte[] hashBytes = SecUtils.getHashBytes(hash);
|
||||
String signatureTxt = SecUtils.signMessageWithKeyBase64(kp, hashBytes, SecUtils.SIG_ALGO_ECDSA, null);
|
||||
System.out.println(formatter.opToJsonNoHash(opOperation));
|
||||
System.out.println(hash);
|
||||
System.out.println(signatureTxt);
|
||||
}
|
||||
|
||||
public static EncodedKeySpec decodeKey(String key) {
|
||||
if (key.startsWith(KEY_BASE64 + ":")) {
|
||||
key = key.substring(KEY_BASE64.length() + 1);
|
||||
int s = key.indexOf(':');
|
||||
if (s == -1) {
|
||||
throw new IllegalArgumentException(String.format("Key doesn't contain algorithm of hashing to verify"));
|
||||
}
|
||||
return getKeySpecByFormat(key.substring(0, s),
|
||||
android.util.Base64.decode(key.substring(s + 1), android.util.Base64.DEFAULT));
|
||||
}
|
||||
throw new IllegalArgumentException(String.format("Key doesn't contain algorithm of hashing to verify"));
|
||||
}
|
||||
|
||||
public static String encodeKey(String algo, PublicKey pk) {
|
||||
if (algo.equals(KEY_BASE64)) {
|
||||
return SecUtils.KEY_BASE64 + ":" + pk.getFormat() + ":" + encodeBase64(pk.getEncoded());
|
||||
}
|
||||
throw new UnsupportedOperationException("Algorithm is not supported: " + algo);
|
||||
}
|
||||
|
||||
public static String encodeKey(String algo, PrivateKey pk) {
|
||||
if (algo.equals(KEY_BASE64)) {
|
||||
return SecUtils.KEY_BASE64 + ":" + pk.getFormat() + ":" + encodeBase64(pk.getEncoded());
|
||||
}
|
||||
throw new UnsupportedOperationException("Algorithm is not supported: " + algo);
|
||||
}
|
||||
|
||||
public static EncodedKeySpec getKeySpecByFormat(String format, byte[] data) {
|
||||
switch (format) {
|
||||
case "PKCS#8":
|
||||
return new PKCS8EncodedKeySpec(data);
|
||||
case "X.509":
|
||||
return new X509EncodedKeySpec(data);
|
||||
}
|
||||
throw new IllegalArgumentException(format);
|
||||
}
|
||||
|
||||
public static String encodeBase64(byte[] data) {
|
||||
return new String(android.util.Base64.decode(data, android.util.Base64.DEFAULT));
|
||||
}
|
||||
|
||||
public static boolean validateKeyPair(String algo, PrivateKey privateKey, PublicKey publicKey)
|
||||
throws FailedVerificationException {
|
||||
if (!algo.equals(ALGO_EC)) {
|
||||
throw new FailedVerificationException("Algorithm is not supported: " + algo);
|
||||
}
|
||||
// create a challenge
|
||||
byte[] challenge = new byte[512];
|
||||
ThreadLocalRandom.current().nextBytes(challenge);
|
||||
|
||||
try {
|
||||
// sign using the private key
|
||||
Signature sig = Signature.getInstance(SIG_ALGO_SHA1_EC);
|
||||
sig.initSign(privateKey);
|
||||
sig.update(challenge);
|
||||
byte[] signature = sig.sign();
|
||||
|
||||
// verify signature using the public key
|
||||
sig.initVerify(publicKey);
|
||||
sig.update(challenge);
|
||||
|
||||
boolean keyPairMatches = sig.verify(signature);
|
||||
return keyPairMatches;
|
||||
} catch (InvalidKeyException e) {
|
||||
throw new FailedVerificationException(e);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new FailedVerificationException(e);
|
||||
} catch (SignatureException e) {
|
||||
throw new FailedVerificationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static KeyPair getKeyPair(String algo, String prKey, String pbKey) throws FailedVerificationException {
|
||||
try {
|
||||
KeyFactory keyFactory = KeyFactory.getInstance(algo);
|
||||
PublicKey pb = null;
|
||||
PrivateKey pr = null;
|
||||
if (pbKey != null) {
|
||||
pb = keyFactory.generatePublic(decodeKey(pbKey));
|
||||
}
|
||||
if (prKey != null) {
|
||||
pr = keyFactory.generatePrivate(decodeKey(prKey));
|
||||
}
|
||||
return new KeyPair(pb, pr);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new FailedVerificationException(e);
|
||||
} catch (InvalidKeySpecException e) {
|
||||
throw new FailedVerificationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static KeyPair generateKeyPairFromPassword(String algo, String keygenMethod, String salt, String pwd)
|
||||
throws FailedVerificationException {
|
||||
if (algo.equals(ALGO_EC)) {
|
||||
return generateECKeyPairFromPassword(keygenMethod, salt, pwd);
|
||||
}
|
||||
throw new UnsupportedOperationException("Unsupported algo keygen method: " + algo);
|
||||
}
|
||||
|
||||
public static KeyPair generateECKeyPairFromPassword(String keygenMethod, String salt, String pwd)
|
||||
throws FailedVerificationException {
|
||||
if (keygenMethod.equals(KEYGEN_PWD_METHOD_1)) {
|
||||
return generateEC256K1KeyPairFromPassword(salt, pwd);
|
||||
}
|
||||
throw new UnsupportedOperationException("Unsupported keygen method: " + keygenMethod);
|
||||
}
|
||||
|
||||
// "EC:secp256k1:scrypt(salt,N:17,r:8,p:1,len:256)" algorithm - EC256K1_S17R8
|
||||
public static KeyPair generateEC256K1KeyPairFromPassword(String salt, String pwd)
|
||||
throws FailedVerificationException {
|
||||
try {
|
||||
KeyPairGenerator kpg = KeyPairGenerator.getInstance(ALGO_EC);
|
||||
ECGenParameterSpec ecSpec = new ECGenParameterSpec(EC_256SPEC_K1);
|
||||
if (pwd.length() < 10) {
|
||||
throw new IllegalArgumentException("Less than 10 characters produces only 50 bit entropy");
|
||||
}
|
||||
byte[] bytes = pwd.getBytes("UTF-8");
|
||||
//byte[] scrypt = SCrypt.generate(bytes, salt.getBytes("UTF-8"), 1 << 17, 8, 1, 256);
|
||||
//kpg.initialize(ecSpec, new FixedSecureRandom(scrypt));
|
||||
return kpg.genKeyPair();
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new FailedVerificationException(e);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new FailedVerificationException(e);
|
||||
} /* catch (InvalidAlgorithmParameterException e) {
|
||||
throw new FailedVerificationException(e);
|
||||
}*/
|
||||
}
|
||||
|
||||
public static KeyPair generateRandomEC256K1KeyPair() throws FailedVerificationException {
|
||||
try {
|
||||
KeyPairGenerator kpg = KeyPairGenerator.getInstance(ALGO_EC);
|
||||
ECGenParameterSpec ecSpec = new ECGenParameterSpec(EC_256SPEC_K1);
|
||||
kpg.initialize(ecSpec);
|
||||
return kpg.genKeyPair();
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new FailedVerificationException(e);
|
||||
} catch (InvalidAlgorithmParameterException e) {
|
||||
throw new FailedVerificationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static String signMessageWithKeyBase64(KeyPair keyPair, byte[] msg, String signAlgo, ByteArrayOutputStream out) {
|
||||
byte[] sigBytes = signMessageWithKey(keyPair, msg, signAlgo);
|
||||
if(out != null) {
|
||||
try {
|
||||
out.write(sigBytes);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
String signature = new String(android.util.Base64.decode(sigBytes, android.util.Base64.DEFAULT));
|
||||
return signAlgo + ":" + DECODE_BASE64 + ":" + signature;
|
||||
}
|
||||
|
||||
public static byte[] signMessageWithKey(KeyPair keyPair, byte[] msg, String signAlgo) {
|
||||
try {
|
||||
Signature sig = Signature.getInstance(getInternalSigAlgo(signAlgo));
|
||||
sig.initSign(keyPair.getPrivate());
|
||||
sig.update(msg);
|
||||
byte[] signatureBytes = sig.sign();
|
||||
return signatureBytes;
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
//throw new FailedVerificationException(e);
|
||||
} catch (InvalidKeyException e) {
|
||||
//throw new FailedVerificationException(e);
|
||||
} catch (SignatureException e) {
|
||||
//throw new FailedVerificationException(e);
|
||||
}
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
public static boolean validateSignature(KeyPair keyPair, byte[] msg, String sig) {
|
||||
if(sig == null || keyPair == null) {
|
||||
return false;
|
||||
}
|
||||
int ind = sig.indexOf(':');
|
||||
String sigAlgo = sig.substring(0, ind);
|
||||
return validateSignature(keyPair, msg, sigAlgo, decodeSignature(sig.substring(ind + 1)));
|
||||
}
|
||||
|
||||
public static boolean validateSignature(KeyPair keyPair, byte[] msg, String sigAlgo, byte[] signature) {
|
||||
if (keyPair == null) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
Signature sig = Signature.getInstance(getInternalSigAlgo(sigAlgo));
|
||||
sig.initVerify(keyPair.getPublic());
|
||||
sig.update(msg);
|
||||
return sig.verify(signature);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
//throw new FailedVerificationException(e);
|
||||
} catch (InvalidKeyException e) {
|
||||
//throw new FailedVerificationException(e);
|
||||
} catch (SignatureException e) {
|
||||
//throw new FailedVerificationException(e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static String getInternalSigAlgo(String sigAlgo) {
|
||||
return sigAlgo.equals(SIG_ALGO_ECDSA)? SIG_ALGO_NONE_EC : sigAlgo;
|
||||
}
|
||||
|
||||
|
||||
public static byte[] calculateHash(String algo, byte[] b1, byte[] b2) {
|
||||
byte[] m = mergeTwoArrays(b1, b2);
|
||||
if (algo.equals(HASH_SHA256)) {
|
||||
return DigestUtils.sha256(m);
|
||||
} else if (algo.equals(HASH_SHA1)) {
|
||||
return DigestUtils.sha1(m);
|
||||
}
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public static byte[] mergeTwoArrays(byte[] b1, byte[] b2) {
|
||||
byte[] m = b1 == null ? b2 : b1;
|
||||
if(b2 != null && b1 != null) {
|
||||
m = new byte[b1.length + b2.length];
|
||||
System.arraycopy(b1, 0, m, 0, b1.length);
|
||||
System.arraycopy(b2, 0, m, b1.length, b2.length);
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
public static String calculateHashWithAlgo(String algo, String salt, String msg) {
|
||||
try {
|
||||
String hex = Hex.encodeHexString(calculateHash(algo, salt == null ? null : salt.getBytes("UTF-8"),
|
||||
msg == null ? null : msg.getBytes("UTF-8")));
|
||||
return algo + ":" + hex;
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static String calculateHashWithAlgo(String algo, byte[] bts) {
|
||||
byte[] hash = calculateHash(algo, bts, null);
|
||||
return formatHashWithAlgo(algo, hash);
|
||||
}
|
||||
|
||||
public static String formatHashWithAlgo(String algo, byte[] hash) {
|
||||
String hex = Hex.encodeHexString(hash);
|
||||
return algo + ":" + hex;
|
||||
}
|
||||
|
||||
public static byte[] getHashBytes(String msg) {
|
||||
if(msg == null || msg.length() == 0) {
|
||||
// special case for empty hash
|
||||
return new byte[0];
|
||||
}
|
||||
int i = msg.lastIndexOf(':');
|
||||
String s = i >= 0 ? msg.substring(i + 1) : msg;
|
||||
try {
|
||||
return Hex.decodeHex(s);
|
||||
} catch (DecoderException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static boolean validateHash(String hash, String salt, String msg) {
|
||||
int s = hash.indexOf(":");
|
||||
if (s == -1) {
|
||||
throw new IllegalArgumentException(String.format("Hash %s doesn't contain algorithm of hashing to verify",
|
||||
s));
|
||||
}
|
||||
String v = calculateHashWithAlgo(hash.substring(0, s), salt, msg);
|
||||
return hash.equals(v);
|
||||
}
|
||||
|
||||
public static byte[] decodeSignature(String digest) {
|
||||
try {
|
||||
int indexOf = digest.indexOf(DECODE_BASE64 + ":");
|
||||
if (indexOf != -1) {
|
||||
// return Base64.getDecoder().decode(digest.substring(indexOf + DECODE_BASE64.length() + 1).
|
||||
// getBytes("UTF-8"));
|
||||
return android.util.Base64.decode(digest.substring(indexOf + DECODE_BASE64.length() + 1)
|
||||
.getBytes("UTF-8"), android.util.Base64.DEFAULT);
|
||||
}
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
throw new IllegalArgumentException("Unknown format for signature " + digest);
|
||||
}
|
||||
|
||||
public static String hexify(byte[] bytes) {
|
||||
if(bytes == null || bytes.length == 0) {
|
||||
return "";
|
||||
}
|
||||
return Hex.encodeHexString(bytes);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -1,530 +0,0 @@
|
|||
package net.osmand.plus.osmedit.utils.ops;
|
||||
|
||||
import com.google.gson.*;
|
||||
import net.osmand.plus.osmedit.utils.util.JsonObjectUtils;
|
||||
import net.osmand.plus.osmedit.utils.util.OUtils;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class OpObject {
|
||||
|
||||
public static final String F_NAME = "name";
|
||||
public static final String F_ID = "id";
|
||||
public static final String F_COMMENT = "comment";
|
||||
public static final String TYPE_OP = "sys.op";
|
||||
public static final String TYPE_BLOCK = "sys.block";
|
||||
public static final String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";
|
||||
// transient info about validation timing etc
|
||||
public static final String F_EVAL = "eval";
|
||||
public static final String F_VALIDATION = "validation";
|
||||
public static final String F_TIMESTAMP_ADDED = "timestamp";
|
||||
public static final String F_PARENT_TYPE = "parentType";
|
||||
public static final String F_PARENT_HASH = "parentHash";
|
||||
public static final String F_CHANGE = "change";
|
||||
public static final String F_CURRENT = "current";
|
||||
// voting
|
||||
public static final String F_OP = "op";
|
||||
public static final String F_STATE = "state";
|
||||
public static final String F_OPEN = "open";
|
||||
public static final String F_FINAL = "final";
|
||||
public static final String F_VOTE = "vote";
|
||||
public static final String F_VOTES = "votes";
|
||||
public static final String F_SUBMITTED_OP_HASH = "submittedOpHash";
|
||||
public static final String F_USER = "user";
|
||||
|
||||
public static final OpObject NULL = new OpObject(true);
|
||||
|
||||
public static SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
|
||||
static {
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
}
|
||||
|
||||
protected Map<String, Object> fields = new TreeMap<>();
|
||||
protected transient Map<String, Object> cacheFields;
|
||||
protected boolean isImmutable;
|
||||
|
||||
protected transient String parentType;
|
||||
protected transient String parentHash;
|
||||
protected transient boolean deleted;
|
||||
|
||||
|
||||
public OpObject() {}
|
||||
|
||||
public OpObject(boolean deleted) {
|
||||
this.deleted = deleted;
|
||||
}
|
||||
|
||||
public OpObject(OpObject cp) {
|
||||
this(cp, false);
|
||||
}
|
||||
|
||||
public OpObject(OpObject cp, boolean copyCacheFields) {
|
||||
createOpObjectCopy(cp, copyCacheFields);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private OpObject createOpObjectCopy(OpObject opObject, boolean copyCacheFields) {
|
||||
this.parentType = opObject.parentType;
|
||||
this.parentHash = opObject.parentHash;
|
||||
this.deleted = opObject.deleted;
|
||||
this.fields = (Map<String, Object>) copyingObjects(opObject.fields, copyCacheFields);
|
||||
if (opObject.cacheFields != null && copyCacheFields) {
|
||||
this.cacheFields = (Map<String, Object>) copyingObjects(opObject.cacheFields, copyCacheFields);
|
||||
}
|
||||
this.isImmutable = false;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isDeleted() {
|
||||
return deleted;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Object copyingObjects(Object object, boolean copyCacheFields) {
|
||||
if (object instanceof Number) {
|
||||
return (Number) object;
|
||||
} else if (object instanceof String) {
|
||||
return (String) object;
|
||||
} else if (object instanceof Boolean) {
|
||||
return (Boolean) object;
|
||||
} else if (object instanceof List) {
|
||||
List<Object> copy = new ArrayList<>();
|
||||
List<Object> list = (List<Object>) object;
|
||||
for (Object o : list) {
|
||||
copy.add(copyingObjects(o, copyCacheFields));
|
||||
}
|
||||
return copy;
|
||||
} else if (object instanceof Map) {
|
||||
Map<Object, Object> copy = new LinkedHashMap<>();
|
||||
Map<Object, Object> map = (Map<Object, Object>) object;
|
||||
for (Object o : map.keySet()) {
|
||||
copy.put(o, copyingObjects(map.get(o), copyCacheFields));
|
||||
}
|
||||
return copy;
|
||||
} else if (object instanceof OpObject) {
|
||||
return new OpObject((OpObject) object);
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Type of object is not supported");
|
||||
}
|
||||
}
|
||||
|
||||
public void setParentOp(OpOperation op) {
|
||||
setParentOp(op.type, op.getRawHash());
|
||||
}
|
||||
|
||||
public void setParentOp(String parentType, String parentHash) {
|
||||
this.parentType = parentType;
|
||||
this.parentHash = parentHash;
|
||||
}
|
||||
|
||||
public String getParentHash() {
|
||||
return parentHash;
|
||||
}
|
||||
|
||||
public String getParentType() {
|
||||
return parentType;
|
||||
}
|
||||
|
||||
public List<String> getId() {
|
||||
return getStringList(F_ID);
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
addOrSetStringValue(F_ID, id);;
|
||||
}
|
||||
|
||||
public boolean isImmutable() {
|
||||
return isImmutable;
|
||||
}
|
||||
|
||||
public OpObject makeImmutable() {
|
||||
isImmutable = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Object getFieldByExpr(String field) {
|
||||
if (field.contains(".") || field.contains("[") || field.contains("]")) {
|
||||
return JsonObjectUtils.getField(this.fields, generateFieldSequence(field));
|
||||
}
|
||||
|
||||
return fields.get(field);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* generateFieldSequence("a") - [a]
|
||||
* generateFieldSequence("a.b") - [a, b]
|
||||
* generateFieldSequence("a.b.c.de") - [a, b, c, de]
|
||||
* generateFieldSequence("a.bwerq.c") - [a, bwerq, c]
|
||||
* generateFieldSequence("a.bwerq...c") - [a, bwerq, c]
|
||||
* generateFieldSequence("a.bwereq..c..") - [a, bwerq, c]
|
||||
* generateFieldSequence("a.{b}") - [a, b]
|
||||
* generateFieldSequence("a.{b.c.de}") - [a, b.c.de]
|
||||
* generateFieldSequence("a.{b.c.de}") - [a, b.c.de]
|
||||
* generateFieldSequence("a.{b{}}") - [a, b{}]
|
||||
* generateFieldSequence("a.{b{}d.q}") - [a, b{}d.q]
|
||||
*/
|
||||
private static List<String> generateFieldSequence(String field) {
|
||||
int STATE_OPEN_BRACE = 1;
|
||||
int STATE_OPEN = 0;
|
||||
int state = STATE_OPEN;
|
||||
int start = 0;
|
||||
List<String> l = new ArrayList<String>();
|
||||
for(int i = 0; i < field.length(); i++) {
|
||||
boolean split = false;
|
||||
if (i == field.length() - 1) {
|
||||
if (state == STATE_OPEN_BRACE) {
|
||||
if(field.charAt(i) == '}') {
|
||||
split = true;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Illegal field expression: " + field);
|
||||
}
|
||||
} else {
|
||||
if(field.charAt(i) != '.') {
|
||||
i++;
|
||||
}
|
||||
split = true;
|
||||
}
|
||||
} else {
|
||||
if (field.charAt(i) == '.' && state == STATE_OPEN) {
|
||||
split = true;
|
||||
} else if (field.charAt(i) == '}' && field.charAt(i + 1) == '.' && state == STATE_OPEN_BRACE) {
|
||||
split = true;
|
||||
} else if (field.charAt(i) == '{' && state == STATE_OPEN) {
|
||||
if(start != i) {
|
||||
throw new IllegalArgumentException("Illegal field expression (wrap {} is necessary): " + field);
|
||||
}
|
||||
state = STATE_OPEN_BRACE;
|
||||
start = i + 1;
|
||||
}
|
||||
}
|
||||
if(split) {
|
||||
if (i != start) {
|
||||
l.add(field.substring(start, i));
|
||||
}
|
||||
start = i + 1;
|
||||
state = STATE_OPEN;
|
||||
}
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
public void setFieldByExpr(String field, Object object) {
|
||||
if (field.contains(".") || field.contains("[") || field.contains("]")) {
|
||||
List<String> fieldSequence = generateFieldSequence(field);
|
||||
if (object == null) {
|
||||
JsonObjectUtils.deleteField(this.fields, fieldSequence);
|
||||
} else {
|
||||
JsonObjectUtils.setField(this.fields, fieldSequence, object);
|
||||
}
|
||||
} else if (object == null) {
|
||||
fields.remove(field);
|
||||
} else {
|
||||
fields.put(field, object);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Object getCacheObject(String f) {
|
||||
if(cacheFields == null) {
|
||||
return null;
|
||||
}
|
||||
return cacheFields.get(f);
|
||||
}
|
||||
|
||||
public void putCacheObject(String f, Object o) {
|
||||
if (isImmutable()) {
|
||||
if (cacheFields == null) {
|
||||
cacheFields = new ConcurrentHashMap<String, Object>();
|
||||
}
|
||||
cacheFields.put(f, o);
|
||||
}
|
||||
}
|
||||
|
||||
public void setId(String id, String id2) {
|
||||
List<String> list = new ArrayList<String>();
|
||||
list.add(id);
|
||||
list.add(id2);
|
||||
putObjectValue(F_ID, list);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return getStringValue(F_NAME);
|
||||
}
|
||||
|
||||
public String getComment() {
|
||||
return getStringValue(F_COMMENT);
|
||||
}
|
||||
|
||||
public Map<String, Object> getRawOtherFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Map<String, String> getStringMap(String field) {
|
||||
return (Map<String, String>) fields.get(field);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Map<String, List<String>> getMapStringList(String field) {
|
||||
return (Map<String, List<String>>) fields.get(field);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<Map<String, String>> getListStringMap(String field) {
|
||||
return (List<Map<String, String>>) fields.get(field);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<Map<String, Object>> getListStringObjMap(String field) {
|
||||
return (List<Map<String, Object>>) fields.get(field);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Map<String, Object> getStringObjMap(String field) {
|
||||
return (Map<String, Object>) fields.get(field);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getField(T def, String... fields) {
|
||||
Map<String, Object> p = this.fields;
|
||||
for(int i = 0; i < fields.length - 1 ; i++) {
|
||||
p = (Map<String, Object>) p.get(fields[i]);
|
||||
if(p == null) {
|
||||
return def;
|
||||
}
|
||||
}
|
||||
T res = (T) p.get(fields[fields.length - 1]);
|
||||
if(res == null) {
|
||||
return def;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Map<List<String>, Object> getStringListObjMap(String field) {
|
||||
return (Map<List<String>, Object>) fields.get(field);
|
||||
}
|
||||
|
||||
|
||||
public long getDate(String field) {
|
||||
String date = getStringValue(field);
|
||||
if(OUtils.isEmpty(date)) {
|
||||
return 0;
|
||||
}
|
||||
try {
|
||||
return dateFormat.parse(date).getTime();
|
||||
} catch (ParseException e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void setDate(String field, long time) {
|
||||
putStringValue(field, dateFormat.format(new Date(time)));
|
||||
}
|
||||
|
||||
public Number getNumberValue(String field) {
|
||||
return (Number) fields.get(field);
|
||||
}
|
||||
|
||||
public int getIntValue(String key, int def) {
|
||||
Number o = getNumberValue(key);
|
||||
return o == null ? def : o.intValue();
|
||||
}
|
||||
|
||||
public long getLongValue(String key, long def) {
|
||||
Number o = getNumberValue(key);
|
||||
return o == null ? def : o.longValue();
|
||||
}
|
||||
|
||||
public String getStringValue(String field) {
|
||||
Object o = fields.get(field);
|
||||
if (o instanceof String || o == null) {
|
||||
return (String) o;
|
||||
}
|
||||
return o.toString();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<String> getStringList(String field) {
|
||||
// cast to list if it is single value
|
||||
Object o = fields.get(field);
|
||||
if(o == null || o.toString().isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
if(o instanceof String) {
|
||||
return Collections.singletonList(o.toString());
|
||||
}
|
||||
return (List<String>) o;
|
||||
}
|
||||
|
||||
public Object getObjectValue(String field) {
|
||||
return fields.get(field);
|
||||
}
|
||||
|
||||
public void putStringValue(String key, String value) {
|
||||
checkNotImmutable();
|
||||
if(value == null) {
|
||||
fields.remove(key);
|
||||
} else {
|
||||
fields.put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Operates as a single value if cardinality is less than 1
|
||||
* or as a list of values if it stores > 1 value
|
||||
* @param key
|
||||
* @param value
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void addOrSetStringValue(String key, String value) {
|
||||
checkNotImmutable();
|
||||
Object o = fields.get(key);
|
||||
if(o == null) {
|
||||
fields.put(key, value);
|
||||
} else if(o instanceof List) {
|
||||
((List<String>) o).add(value);
|
||||
} else {
|
||||
List<String> list = new ArrayList<String>();
|
||||
list.add(o.toString());
|
||||
list.add(value);
|
||||
fields.put(key, list);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Map<String, Object> getChangedEditFields() {
|
||||
return (Map<String, Object>) fields.get(F_CHANGE);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Map<String, Object> getCurrentEditFields() {
|
||||
return (Map<String, Object>) fields.get(F_CURRENT);
|
||||
}
|
||||
|
||||
public void putObjectValue(String key, Object value) {
|
||||
checkNotImmutable();
|
||||
if(value == null) {
|
||||
fields.remove(key);
|
||||
} else {
|
||||
fields.put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
public void checkNotImmutable() {
|
||||
if(isImmutable) {
|
||||
throw new IllegalStateException("Object is immutable");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void checkImmutable() {
|
||||
if(!isImmutable) {
|
||||
throw new IllegalStateException("Object is mutable");
|
||||
}
|
||||
}
|
||||
|
||||
public Object remove(String key) {
|
||||
checkNotImmutable();
|
||||
return fields.remove(key);
|
||||
}
|
||||
|
||||
public Map<String, Object> getMixedFieldsAndCacheMap() {
|
||||
TreeMap<String, Object> mp = new TreeMap<>(fields);
|
||||
if(cacheFields != null || parentType != null || parentHash != null) {
|
||||
TreeMap<String, Object> eval = new TreeMap<String, Object>();
|
||||
|
||||
if(parentType != null) {
|
||||
eval.put(F_PARENT_TYPE, parentType);
|
||||
}
|
||||
if(parentHash != null) {
|
||||
eval.put(F_PARENT_HASH, parentHash);
|
||||
}
|
||||
if (cacheFields != null) {
|
||||
Iterator<Entry<String, Object>> it = cacheFields.entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
Entry<String, Object> e = it.next();
|
||||
Object v = e.getValue();
|
||||
if (v instanceof Map || v instanceof String || v instanceof Number) {
|
||||
eval.put(e.getKey(), v);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(eval.size() > 0) {
|
||||
mp.put(F_EVAL, eval);
|
||||
}
|
||||
}
|
||||
return mp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((fields == null) ? 0 : fields.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName() + "[" + fields + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
OpObject other = (OpObject) obj;
|
||||
if (fields == null) {
|
||||
if (other.fields != null)
|
||||
return false;
|
||||
} else if (!fields.equals(other.fields))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static class OpObjectAdapter implements JsonDeserializer<OpObject>,
|
||||
JsonSerializer<OpObject> {
|
||||
|
||||
private boolean fullOutput;
|
||||
|
||||
public OpObjectAdapter(boolean fullOutput) {
|
||||
this.fullOutput = fullOutput;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OpObject deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
||||
throws JsonParseException {
|
||||
OpObject bn = new OpObject();
|
||||
bn.fields = context.deserialize(json, TreeMap.class);
|
||||
// remove cache
|
||||
bn.fields.remove(F_EVAL);
|
||||
return bn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement serialize(OpObject src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
return context.serialize(fullOutput ? src.getMixedFieldsAndCacheMap() : src.fields);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -1,281 +0,0 @@
|
|||
package net.osmand.plus.osmedit.utils.ops;
|
||||
|
||||
import com.google.gson.*;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.*;
|
||||
|
||||
public class OpOperation extends OpObject {
|
||||
|
||||
public static final String F_TYPE = "type";
|
||||
public static final String F_SIGNED_BY = "signed_by";
|
||||
public static final String F_HASH = "hash";
|
||||
|
||||
public static final String F_SIGNATURE = "signature";
|
||||
|
||||
public static final String F_REF = "ref";
|
||||
public static final String F_CREATE = "create";
|
||||
public static final String F_DELETE = "delete";
|
||||
public static final String F_EDIT = "edit";
|
||||
|
||||
public static final String F_NAME = "name";
|
||||
public static final String F_COMMENT = "comment";
|
||||
|
||||
private List<OpObject> createdObjects = new LinkedList<OpObject>();
|
||||
private List<OpObject> editedObjects = new LinkedList<OpObject>();
|
||||
protected String type;
|
||||
|
||||
public OpOperation() {
|
||||
}
|
||||
|
||||
public OpOperation(OpOperation cp, boolean copyCacheFields) {
|
||||
super(cp, copyCacheFields);
|
||||
this.type = cp.type;
|
||||
for(OpObject o : cp.createdObjects) {
|
||||
this.createdObjects.add(new OpObject(o, copyCacheFields));
|
||||
}
|
||||
for(OpObject o : cp.editedObjects) {
|
||||
this.editedObjects.add(new OpObject(o, copyCacheFields));
|
||||
}
|
||||
}
|
||||
|
||||
public String getOperationType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String name) {
|
||||
checkNotImmutable();
|
||||
type = name;
|
||||
updateObjectsRef();
|
||||
}
|
||||
|
||||
protected void updateObjectsRef() {
|
||||
for(OpObject o : createdObjects) {
|
||||
o.setParentOp(this);
|
||||
}
|
||||
for(OpObject o : editedObjects) {
|
||||
o.setParentOp(this);
|
||||
}
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public OpOperation makeImmutable() {
|
||||
isImmutable = true;
|
||||
for(OpObject o : createdObjects) {
|
||||
o.makeImmutable();
|
||||
}
|
||||
for(OpObject o : editedObjects) {
|
||||
o.makeImmutable();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public void setSignedBy(String value) {
|
||||
putStringValue(F_SIGNED_BY, value);
|
||||
}
|
||||
|
||||
public void addOtherSignedBy(String value) {
|
||||
super.addOrSetStringValue(F_SIGNED_BY, value);
|
||||
}
|
||||
|
||||
public List<String> getSignedBy() {
|
||||
return getStringList(F_SIGNED_BY);
|
||||
}
|
||||
|
||||
public String getHash() {
|
||||
return getStringValue(F_HASH);
|
||||
}
|
||||
|
||||
public String getRawHash() {
|
||||
String rw = getStringValue(F_HASH);
|
||||
// drop algorithm and everything else
|
||||
if(rw != null) {
|
||||
rw = rw.substring(rw.lastIndexOf(':') + 1);
|
||||
}
|
||||
return rw;
|
||||
}
|
||||
|
||||
public List<String> getSignatureList() {
|
||||
return getStringList(F_SIGNATURE);
|
||||
}
|
||||
|
||||
public Map<String, List<String>> getRef() {
|
||||
return getMapStringList(F_REF);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<List<String>> getDeleted() {
|
||||
List<List<String>> l = (List<List<String>>) fields.get(F_DELETE);
|
||||
if(l == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
public boolean hasDeleted() {
|
||||
return getDeleted().size() > 0;
|
||||
}
|
||||
|
||||
public void addDeleted(List<String> id) {
|
||||
if(!fields.containsKey(F_DELETE)) {
|
||||
ArrayList<List<String>> lst = new ArrayList<>();
|
||||
lst.add(id);
|
||||
putObjectValue(F_DELETE, lst);
|
||||
} else {
|
||||
getDeleted().add(id);
|
||||
}
|
||||
}
|
||||
|
||||
public List<OpObject> getCreated() {
|
||||
return createdObjects;
|
||||
}
|
||||
|
||||
public void addCreated(OpObject o) {
|
||||
checkNotImmutable();
|
||||
createdObjects.add(o);
|
||||
if(type != null) {
|
||||
o.setParentOp(this);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasCreated() {
|
||||
return createdObjects.size() > 0;
|
||||
}
|
||||
|
||||
public void addEdited(OpObject o) {
|
||||
checkNotImmutable();
|
||||
editedObjects.add(o);
|
||||
if (type != null) {
|
||||
o.setParentOp(this);
|
||||
}
|
||||
}
|
||||
|
||||
public List<OpObject> getEdited() {
|
||||
return editedObjects;
|
||||
}
|
||||
|
||||
public boolean hasEdited() {
|
||||
return editedObjects.size() > 0;
|
||||
}
|
||||
|
||||
|
||||
public String getName() {
|
||||
return getStringValue(F_NAME);
|
||||
}
|
||||
|
||||
public String getComment() {
|
||||
return getStringValue(F_COMMENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = super.hashCode();
|
||||
result = prime * result + ((createdObjects == null) ? 0 : createdObjects.hashCode());
|
||||
result = prime * result + ((editedObjects == null) ? 0 : editedObjects.hashCode());
|
||||
result = prime * result + ((type == null) ? 0 : type.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (!super.equals(obj))
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
OpOperation other = (OpOperation) obj;
|
||||
if (createdObjects == null) {
|
||||
if (other.createdObjects != null)
|
||||
return false;
|
||||
} else if (!createdObjects.equals(other.createdObjects))
|
||||
return false;
|
||||
if (editedObjects == null) {
|
||||
if (other.editedObjects != null)
|
||||
return false;
|
||||
} else if (!editedObjects.equals(other.editedObjects))
|
||||
return false;
|
||||
if (type == null) {
|
||||
if (other.type != null)
|
||||
return false;
|
||||
} else if (!type.equals(other.type))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static class OpOperationBeanAdapter implements JsonDeserializer<OpOperation>,
|
||||
JsonSerializer<OpOperation> {
|
||||
|
||||
// plain serialization to calculate hash
|
||||
private boolean excludeHashAndSignature;
|
||||
private boolean fullOutput;
|
||||
|
||||
public OpOperationBeanAdapter(boolean fullOutput, boolean excludeHashAndSignature) {
|
||||
this.excludeHashAndSignature = excludeHashAndSignature;
|
||||
this.fullOutput = fullOutput;
|
||||
}
|
||||
|
||||
public OpOperationBeanAdapter(boolean fullOutput) {
|
||||
this.fullOutput = fullOutput;
|
||||
this.excludeHashAndSignature = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OpOperation deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
||||
throws JsonParseException {
|
||||
JsonObject jsonObj = json.getAsJsonObject();
|
||||
OpOperation op = new OpOperation();
|
||||
JsonElement tp = jsonObj.remove(F_TYPE);
|
||||
if(tp != null) {
|
||||
String opType = tp.getAsString();
|
||||
op.type = opType;
|
||||
} else {
|
||||
op.type = "";
|
||||
}
|
||||
JsonElement createdObjs = jsonObj.remove(F_CREATE);
|
||||
if(createdObjs != null) {
|
||||
JsonArray ar = createdObjs.getAsJsonArray();
|
||||
for(int i = 0; i < ar.size(); i++) {
|
||||
//op.addCreated(context.deserialize(ar.get(i), OpObject.class));
|
||||
}
|
||||
}
|
||||
|
||||
JsonElement editedObjs = jsonObj.remove(F_EDIT);
|
||||
if (editedObjs != null) {
|
||||
for (JsonElement editElem : editedObjs.getAsJsonArray()) {
|
||||
//op.addEdited(context.deserialize(editElem, OpObject.class));
|
||||
}
|
||||
}
|
||||
|
||||
jsonObj.remove(F_EVAL);
|
||||
op.fields = context.deserialize(jsonObj, TreeMap.class);
|
||||
return op;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement serialize(OpOperation src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
TreeMap<String, Object> tm = new TreeMap<>(fullOutput ? src.getMixedFieldsAndCacheMap() : src.fields);
|
||||
if(excludeHashAndSignature) {
|
||||
tm.remove(F_SIGNATURE);
|
||||
tm.remove(F_HASH);
|
||||
}
|
||||
tm.put(F_TYPE, src.type);
|
||||
|
||||
if (src.hasEdited()) {
|
||||
tm.put(F_EDIT, context.serialize(src.editedObjects));
|
||||
}
|
||||
|
||||
if(src.hasCreated()) {
|
||||
tm.put(F_CREATE, context.serialize(src.createdObjects));
|
||||
}
|
||||
return context.serialize(tm);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,171 +0,0 @@
|
|||
package net.osmand.plus.osmedit.utils.ops;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
public class PerformanceMetrics {
|
||||
private static final PerformanceMetrics inst = new PerformanceMetrics();
|
||||
public static final int METRICS_COUNT = 2;
|
||||
public static PerformanceMetrics i() {
|
||||
return inst;
|
||||
}
|
||||
private final Map<String, PerformanceMetric> metrics = new ConcurrentHashMap<String, PerformanceMetric>();
|
||||
private final AtomicInteger ids = new AtomicInteger();
|
||||
private final PerformanceMetric DISABLED = new PerformanceMetric(-1, "<disabled>");
|
||||
private boolean enabled = true;
|
||||
private PerformanceMetric overhead;
|
||||
|
||||
private PerformanceMetrics() {
|
||||
overhead = getByKey("_overhead");
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public Map<String, PerformanceMetric> getMetrics() {
|
||||
return metrics;
|
||||
}
|
||||
|
||||
public PerformanceMetric getMetric(String prefix, String key) {
|
||||
if(!enabled) {
|
||||
return DISABLED;
|
||||
}
|
||||
return getMetric(prefix + "." + key);
|
||||
}
|
||||
|
||||
public void reset(int c) {
|
||||
for(PerformanceMetric p : metrics.values()) {
|
||||
p.reset(c);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public PerformanceMetric getMetric(String key) {
|
||||
if(!enabled) {
|
||||
return DISABLED;
|
||||
}
|
||||
long s = System.nanoTime();
|
||||
PerformanceMetric pm = getByKey(key);
|
||||
overhead.capture(System.nanoTime() - s);
|
||||
return pm;
|
||||
}
|
||||
|
||||
private PerformanceMetric getByKey(String key) {
|
||||
PerformanceMetric pm = metrics.get(key);
|
||||
if(pm == null) {
|
||||
pm = new PerformanceMetric(ids.incrementAndGet(), key);
|
||||
metrics.put(key, pm);
|
||||
}
|
||||
return pm;
|
||||
}
|
||||
|
||||
|
||||
public final class PerformanceMetric {
|
||||
final String name;
|
||||
final int id;
|
||||
String description;
|
||||
AtomicInteger invocations = new AtomicInteger();
|
||||
AtomicLong totalDuration = new AtomicLong();
|
||||
AtomicInteger invocationsA = new AtomicInteger();
|
||||
AtomicLong totalDurationA = new AtomicLong();
|
||||
AtomicInteger invocationsB = new AtomicInteger();
|
||||
AtomicLong totalDurationB = new AtomicLong();
|
||||
|
||||
|
||||
|
||||
private PerformanceMetric(int id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Metric start() {
|
||||
if(id == -1) {
|
||||
return Metric.EMPTY;
|
||||
}
|
||||
return new Metric(this);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void reset(int c) {
|
||||
if(c == 1) {
|
||||
invocationsA.set(0);
|
||||
totalDurationA.set(0);
|
||||
} else if(c == 2) {
|
||||
totalDurationB.set(0);
|
||||
invocationsB.set(0);
|
||||
}
|
||||
}
|
||||
|
||||
public int getInvocations(int c) {
|
||||
if(c == 1) {
|
||||
return invocationsA.get();
|
||||
} else if(c == 2) {
|
||||
return invocationsB.get();
|
||||
}
|
||||
return invocations.get();
|
||||
}
|
||||
|
||||
public long getDuration(int c) {
|
||||
if(c == 1) {
|
||||
return totalDurationA.get();
|
||||
} else if(c == 2) {
|
||||
return totalDurationB.get();
|
||||
}
|
||||
return totalDuration.get();
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
long capture(long d) {
|
||||
invocations.incrementAndGet();
|
||||
totalDuration.addAndGet(d);
|
||||
invocationsA.incrementAndGet();
|
||||
totalDurationA.addAndGet(d);
|
||||
invocationsB.incrementAndGet();
|
||||
totalDurationB.addAndGet(d);
|
||||
return d;
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Metric {
|
||||
long start;
|
||||
PerformanceMetric m;
|
||||
boolean e;
|
||||
public static final Metric EMPTY = new Metric(true);
|
||||
private Metric(PerformanceMetric m) {
|
||||
start = System.nanoTime();
|
||||
this.m = m;
|
||||
}
|
||||
|
||||
private Metric(boolean empty) {
|
||||
e = empty;
|
||||
}
|
||||
|
||||
public long capture() {
|
||||
if(e) {
|
||||
return 0;
|
||||
}
|
||||
return m.capture(System.nanoTime() - start);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
package net.osmand.plus.osmedit.utils.util;
|
||||
|
||||
public interface DBConstants {
|
||||
|
||||
public static final String SCHEMA_NAME = "public";
|
||||
|
||||
// Tables
|
||||
public static final String BLOCK_TABLE = "blocks";
|
||||
|
||||
public static final String LOGINS_TABLE = "logins";
|
||||
|
||||
public static final String USERS_TABLE = "users";
|
||||
|
||||
public static final String QUEUE_TABLE = "queue";
|
||||
|
||||
public static final String ROLES_TABLE = "roles";
|
||||
|
||||
public static final String TABLES_TABLE = "tables";
|
||||
|
||||
public static final String OP_DEFINITIONS_TABLE = "op_definitions";
|
||||
|
||||
public static final String EXECUTED_OPERATIONS_TABLE = "operations";
|
||||
|
||||
|
||||
}
|
|
@ -1,275 +0,0 @@
|
|||
package net.osmand.plus.osmedit.utils.util;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* Class uses for work with Json Object represent as Map.
|
||||
*/
|
||||
public class JsonObjectUtils {
|
||||
|
||||
|
||||
private static final int GET_OPERATION = 0;
|
||||
private static final int SET_OPERATION = 1;
|
||||
private static final int DELETE_OPERATION = 2;
|
||||
protected static final Log LOGGER = LogFactory.getLog(JsonObjectUtils.class);
|
||||
|
||||
private static class OperationAccess {
|
||||
private final int operation;
|
||||
private final Object value;
|
||||
|
||||
private OperationAccess(int op, Object v) {
|
||||
this.operation = op;
|
||||
this.value = v;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve value from jsonMap by field sequence.
|
||||
* @param jsonMap source json object deserialized in map
|
||||
* @param fieldSequence Sequence to field value.
|
||||
* Example: person.car.number have to be ["person", "car[2]", "number"]
|
||||
* @return Field value
|
||||
*/
|
||||
public static Object getField(Map<String, Object> jsonMap, String[] fieldSequence) {
|
||||
return accessField(jsonMap, fieldSequence, new OperationAccess(GET_OPERATION, null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set value to json field (path to field presented as sequence of string)
|
||||
*
|
||||
* @param jsonMap source json object deserialized in map
|
||||
* @param fieldSequence Sequence to field value.
|
||||
* * Example: person.car.number have to be ["person", "car[2]", "number"]
|
||||
* @param field field value
|
||||
* @return
|
||||
*/
|
||||
public static Object setField(Map<String, Object> jsonMap, List<String> fieldSequence, Object field) {
|
||||
return setField(jsonMap, fieldSequence.toArray(new String[fieldSequence.size()]), field);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set value to json field (path to field presented as sequence of string)
|
||||
*
|
||||
* @param jsonObject source json object deserialized in map
|
||||
* @param fieldSequence Sequence to field value.
|
||||
* * Example: person.car.number have to be ["person", "car[2]", "number"]
|
||||
* @param field field value
|
||||
* @return
|
||||
*/
|
||||
public static Object setField(Map<String, Object> jsonObject, String[] fieldSequence, Object field) {
|
||||
return accessField(jsonObject, fieldSequence, new OperationAccess(SET_OPERATION, field));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve value from jsonMap by field sequence.
|
||||
*
|
||||
* @param jsonObject source json object deserialized in map
|
||||
* @param fieldSequence Sequence to field value.
|
||||
* Example: person.car.number have to be ["person", "car[2]", "number"]
|
||||
* @return Field value
|
||||
*/
|
||||
public static Object getField(Map<String, Object> jsonObject, List<String> fieldSequence) {
|
||||
return getField(jsonObject, fieldSequence.toArray(new String[fieldSequence.size()]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete field value from json Map (field path presented as sequence of string)
|
||||
*
|
||||
* @param jsonMap source json object deserialized in map
|
||||
* @param fieldSequence Sequence to field value.
|
||||
* Example: person.car.number have to be ["person", "car[2]", "number"]
|
||||
* @return
|
||||
*/
|
||||
public static Object deleteField(Map<String, Object> jsonMap, List<String> fieldSequence) {
|
||||
return accessField(jsonMap, fieldSequence.toArray(new String[fieldSequence.size()]), new OperationAccess(DELETE_OPERATION, null));
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static Object accessField(Map<String, Object> jsonObject, String[] fieldSequence, OperationAccess op) {
|
||||
if (fieldSequence == null || fieldSequence.length == 0) {
|
||||
throw new IllegalArgumentException("Field sequence is empty. Set value to root not possible.");
|
||||
}
|
||||
String fieldName = null;
|
||||
Map<String, Object> jsonObjLocal = jsonObject;
|
||||
List<Object> jsonListLocal = null;
|
||||
int indexToAccess = -1;
|
||||
for(int i = 0; i < fieldSequence.length; i++) {
|
||||
boolean last = i == fieldSequence.length - 1;
|
||||
fieldName = fieldSequence[i];
|
||||
int indOpArray = -1;
|
||||
for(int ic = 0; ic < fieldName.length(); ) {
|
||||
if(ic > 0 && (fieldName.charAt(ic) == '[' || fieldName.charAt(ic) == ']') &&
|
||||
fieldName.charAt(ic - 1) == '\\') {
|
||||
// replace '\[' with '['
|
||||
fieldName = fieldName.substring(0, ic - 1) + fieldName.substring(ic);
|
||||
} else if(fieldName.charAt(ic) == '[') {
|
||||
indOpArray = ic;
|
||||
break;
|
||||
} else {
|
||||
ic++;
|
||||
}
|
||||
}
|
||||
jsonListLocal = null; // reset
|
||||
if(indOpArray == -1) {
|
||||
if(!last) {
|
||||
Map<String, Object> fieldAccess = (Map<String, Object>) jsonObjLocal.get(fieldName);
|
||||
if(fieldAccess == null) {
|
||||
if(op.operation == GET_OPERATION) {
|
||||
// don't modify during get operation
|
||||
return null;
|
||||
}
|
||||
Map<String, Object> newJsonMap = new TreeMap<>();
|
||||
jsonObjLocal.put(fieldName, newJsonMap);
|
||||
jsonObjLocal = newJsonMap;
|
||||
} else {
|
||||
jsonObjLocal = fieldAccess;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
String arrayFieldName = fieldName.substring(0, indOpArray);
|
||||
if(arrayFieldName.contains("]")) {
|
||||
throw new IllegalArgumentException(String.format("Illegal field array modifier %s", fieldSequence[i]));
|
||||
}
|
||||
jsonListLocal = (List<Object>) jsonObjLocal.get(arrayFieldName);
|
||||
if (jsonListLocal == null) {
|
||||
if (op.operation == GET_OPERATION) {
|
||||
// don't modify during get operation
|
||||
return null;
|
||||
}
|
||||
jsonListLocal = new ArrayList<Object>();
|
||||
jsonObjLocal.put(arrayFieldName, jsonListLocal);
|
||||
}
|
||||
while (indOpArray != -1) {
|
||||
fieldName = fieldName.substring(indOpArray + 1);
|
||||
int indClArray = fieldName.indexOf("]");
|
||||
if (indClArray == -1) {
|
||||
throw new IllegalArgumentException(String.format("Illegal field array modifier %s", fieldSequence[i]));
|
||||
}
|
||||
if(indClArray == fieldName.length() - 1) {
|
||||
indOpArray = -1;
|
||||
} else if(fieldName.charAt(indClArray + 1) == '[') {
|
||||
indOpArray = indClArray + 1;
|
||||
} else {
|
||||
throw new IllegalArgumentException(String.format("Illegal field array modifier %s", fieldSequence[i]));
|
||||
}
|
||||
int index = Integer.parseInt(fieldName.substring(0, indClArray));
|
||||
if (last && indOpArray == -1) {
|
||||
indexToAccess = index;
|
||||
} else {
|
||||
Object obj = null;
|
||||
if (index < jsonListLocal.size() && index >= 0) {
|
||||
obj = jsonListLocal.get(index);
|
||||
} else if (op.operation == SET_OPERATION && (index == -1 || index == jsonListLocal.size())) {
|
||||
index = jsonListLocal.size();
|
||||
jsonListLocal.add(null);
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Illegal access to array at position %d", index));
|
||||
}
|
||||
|
||||
if (obj == null) {
|
||||
if (op.operation == GET_OPERATION) {
|
||||
// don't modify during get operation
|
||||
return null;
|
||||
}
|
||||
if (indOpArray == -1) {
|
||||
obj = new TreeMap<>();
|
||||
} else {
|
||||
obj = new ArrayList<Object>();
|
||||
}
|
||||
jsonListLocal.set(index, obj);
|
||||
}
|
||||
if(indOpArray != -1) {
|
||||
jsonListLocal = (List<Object>) obj;
|
||||
} else {
|
||||
jsonObjLocal = (Map<String, Object>) obj;
|
||||
jsonListLocal = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if(jsonListLocal != null) {
|
||||
return accessListField(op, jsonListLocal, indexToAccess);
|
||||
} else {
|
||||
return accessObjField(op, jsonObjLocal, fieldName);
|
||||
}
|
||||
}
|
||||
|
||||
private static Object accessObjField(OperationAccess op, Map<String, Object> jsonObjLocal, String fieldName) {
|
||||
Object prevValue;
|
||||
if (op.operation == DELETE_OPERATION) {
|
||||
prevValue = jsonObjLocal.remove(fieldName);
|
||||
} else if (op.operation == SET_OPERATION) {
|
||||
prevValue = jsonObjLocal.put(fieldName, op.value);
|
||||
} else {
|
||||
prevValue = jsonObjLocal.get(fieldName);
|
||||
}
|
||||
return prevValue;
|
||||
}
|
||||
|
||||
private static Object accessListField(OperationAccess op, List<Object> jsonListLocal, int indexToAccess) {
|
||||
Object prevValue;
|
||||
int lastIndex = indexToAccess;
|
||||
if (op.operation == DELETE_OPERATION) {
|
||||
if (lastIndex >= jsonListLocal.size() || lastIndex < 0) {
|
||||
prevValue = null;
|
||||
} else {
|
||||
prevValue = jsonListLocal.remove(lastIndex);
|
||||
}
|
||||
} else if (op.operation == SET_OPERATION) {
|
||||
if (lastIndex == jsonListLocal.size() || lastIndex == -1) {
|
||||
prevValue = null;
|
||||
jsonListLocal.add(op.value);
|
||||
} else if (lastIndex >= jsonListLocal.size() || lastIndex < 0) {
|
||||
throw new IllegalArgumentException(String.format("Illegal access to %d position in array with size %d",
|
||||
lastIndex, jsonListLocal.size()));
|
||||
} else {
|
||||
prevValue = jsonListLocal.set(lastIndex, op.value);
|
||||
}
|
||||
} else {
|
||||
if (lastIndex >= jsonListLocal.size() || lastIndex < 0) {
|
||||
prevValue = null;
|
||||
} else {
|
||||
prevValue = jsonListLocal.get(lastIndex);
|
||||
}
|
||||
}
|
||||
return prevValue;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static List<Object> getIndexObjectByField(Object obj, List<String> field, List<Object> res) {
|
||||
if(obj == null) {
|
||||
return res;
|
||||
}
|
||||
if(field.size() == 0) {
|
||||
if(res == null) {
|
||||
res = new ArrayList<Object>();
|
||||
}
|
||||
res.add(obj);
|
||||
return res;
|
||||
}
|
||||
if (obj instanceof Map) {
|
||||
String fieldFirst = field.get(0);
|
||||
Object value = ((Map<String, Object>) obj).get(fieldFirst);
|
||||
return getIndexObjectByField(value, field.subList(1, field.size()), res);
|
||||
} else if(obj instanceof Collection) {
|
||||
for(Object o : ((Collection<Object>)obj)) {
|
||||
res = getIndexObjectByField(o, field, res);
|
||||
}
|
||||
} else {
|
||||
// we need extract but there no field
|
||||
LOGGER.warn(String.format("Can't access field %s for object %s", field, obj));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,122 +0,0 @@
|
|||
package net.osmand.plus.osmedit.utils.util;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class OUtils {
|
||||
|
||||
public static boolean isEmpty(String s) {
|
||||
return s == null || s.trim().length() == 0;
|
||||
}
|
||||
|
||||
public static boolean validateSqlIdentifier(String id, StringBuilder errorMessage, String field, String action) {
|
||||
if(isEmpty(id)) {
|
||||
errorMessage.append(String.format("Field '%s' is not specified which is necessary to %s", field, action));
|
||||
return false;
|
||||
}
|
||||
if(!isValidJavaIdentifier(id)) {
|
||||
errorMessage.append(String.format("Value '%s' is not valid for %s to %s", id, field, action));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static long combine(int x1, int x2) {
|
||||
long l = Integer.toUnsignedLong(x1);
|
||||
l = (l << 32) | Integer.toUnsignedLong(x2);
|
||||
return l;
|
||||
}
|
||||
|
||||
public static int first(long l) {
|
||||
long s = Integer.MAX_VALUE;
|
||||
int t = (int) ((l & (s << 32)) >> 32);
|
||||
if(l < 0) {
|
||||
t = -t;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
public static int second(long l) {
|
||||
int t = (int) (l & Integer.MAX_VALUE);
|
||||
if ((l & 0x80000000l) != 0) {
|
||||
t = -t;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
public static boolean isValidJavaIdentifier(String s) {
|
||||
if (s.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
if (!Character.isJavaIdentifierStart(s.charAt(0))) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 1; i < s.length(); i++) {
|
||||
if (!Character.isJavaIdentifierPart(s.charAt(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean equals(List<?> s1, List<?> s2) {
|
||||
if(s1 == null || s1.size() == 0) {
|
||||
return s2 == null || s2.size() == 0;
|
||||
}
|
||||
if(s2 == null || s1.size() != s2.size()) {
|
||||
return false;
|
||||
}
|
||||
for(int i = 0; i < s1.size(); i++) {
|
||||
Object o1 = s1.get(i);
|
||||
Object o2 = s2.get(i);
|
||||
if(o1 == null) {
|
||||
if(o2 != null) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if(!o1.equals(o2)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
public static boolean equals(Object s1, Object s2) {
|
||||
if(s1 == null || s2 == null) {
|
||||
return s1 == s2;
|
||||
}
|
||||
if(s1 instanceof Number && s2 instanceof Number) {
|
||||
return ((Number) s1).longValue() == ((Number) s2).longValue() &&
|
||||
((Number) s1).doubleValue() == ((Number) s2).doubleValue();
|
||||
}
|
||||
return s1.equals(s2);
|
||||
}
|
||||
|
||||
public static boolean equalsStringValue(Object s1, Object s2) {
|
||||
if(s1 == null || s2 == null) {
|
||||
return s1 == s2;
|
||||
}
|
||||
return s1.toString().equals(s2.toString());
|
||||
}
|
||||
|
||||
public static long parseLongSilently(String input, long def) {
|
||||
if (input != null && input.length() > 0) {
|
||||
try {
|
||||
return Long.parseLong(input);
|
||||
} catch (NumberFormatException e) {
|
||||
return def;
|
||||
}
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
public static int parseIntSilently(String input, int def) {
|
||||
if (input != null && input.length() > 0) {
|
||||
try {
|
||||
return Integer.parseInt(input);
|
||||
} catch (NumberFormatException e) {
|
||||
return def;
|
||||
}
|
||||
}
|
||||
return def;
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
package net.osmand.plus.osmedit.utils.util.exception;
|
||||
|
||||
public class ConnectionException extends TechnicalException {
|
||||
|
||||
private static final long serialVersionUID = 8191498058841215578L;
|
||||
|
||||
public ConnectionException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public ConnectionException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
package net.osmand.plus.osmedit.utils.util.exception;
|
||||
|
||||
public class FailedVerificationException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = -4936205097177668159L;
|
||||
|
||||
|
||||
public FailedVerificationException(Exception e) {
|
||||
super(e);
|
||||
}
|
||||
|
||||
|
||||
public FailedVerificationException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
package net.osmand.plus.osmedit.utils.util.exception;
|
||||
|
||||
public class TechnicalException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 9201898433665734132L;
|
||||
|
||||
public TechnicalException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public TechnicalException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue