| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| package org.apache.sysds.runtime.privacy; |
| |
| import java.io.Externalizable; |
| import java.io.IOException; |
| import java.io.ObjectInput; |
| import java.io.ObjectOutput; |
| import java.util.Arrays; |
| import java.util.List; |
| import java.util.Map.Entry; |
| import java.util.stream.Collectors; |
| |
| import org.apache.sysds.parser.DataExpression; |
| import org.apache.sysds.runtime.privacy.finegrained.DataRange; |
| import org.apache.sysds.runtime.privacy.finegrained.FineGrainedPrivacy; |
| import org.apache.sysds.runtime.privacy.finegrained.FineGrainedPrivacyList; |
| import org.apache.wink.json4j.JSONArray; |
| import org.apache.wink.json4j.JSONException; |
| import org.apache.wink.json4j.JSONObject; |
| import org.apache.wink.json4j.OrderedJSONObject; |
| |
| /** |
| * PrivacyConstraint holds all privacy constraints for data in the system at |
| * compile time and runtime. |
| */ |
| public class PrivacyConstraint implements Externalizable |
| { |
| public enum PrivacyLevel { |
| None, // No data exchange constraints. Data can be shared with anyone. |
| Private, // Data cannot leave the origin. |
| PrivateAggregation // Only aggregations of the data can leave the origin. |
| } |
| |
| protected PrivacyLevel privacyLevel = PrivacyLevel.None; |
| protected FineGrainedPrivacy fineGrainedPrivacy; |
| |
| /** |
| * Basic Constructor with a fine-grained collection |
| * based on a list implementation. |
| */ |
| public PrivacyConstraint(){ |
| this(new FineGrainedPrivacyList()); |
| } |
| |
| /** |
| * Constructor with the option to choose between |
| * different fine-grained collection implementations. |
| * @param fineGrainedPrivacyCollection the instance in which fine-grained constraints are stored |
| */ |
| public PrivacyConstraint(FineGrainedPrivacy fineGrainedPrivacyCollection){ |
| setFineGrainedPrivacyConstraints(fineGrainedPrivacyCollection); |
| } |
| |
| /** |
| * Constructor with default fine-grained collection implementation |
| * where the entire data object is set to the given privacy level. |
| * @param privacyLevel for the entire data object. |
| */ |
| public PrivacyConstraint(PrivacyLevel privacyLevel) { |
| this(); |
| setPrivacyLevel(privacyLevel); |
| } |
| |
| public void setPrivacyLevel(PrivacyLevel privacyLevel){ |
| this.privacyLevel = privacyLevel; |
| } |
| |
| public PrivacyLevel getPrivacyLevel(){ |
| return privacyLevel; |
| } |
| |
| /** |
| * Checks if fine-grained privacy is set for this privacy constraint. |
| * @return true if the privacy constraint has fine-grained constraints. |
| */ |
| public boolean hasFineGrainedConstraints(){ |
| return fineGrainedPrivacy.hasConstraints(); |
| } |
| |
| /** |
| * Sets fine-grained privacy for the privacy constraint. |
| * Existing fine-grained privacy collection will be overwritten. |
| * @param fineGrainedPrivacy fine-grained privacy instance which is set for the privacy constraint |
| */ |
| public void setFineGrainedPrivacyConstraints(FineGrainedPrivacy fineGrainedPrivacy){ |
| this.fineGrainedPrivacy = fineGrainedPrivacy; |
| } |
| |
| /** |
| * Get fine-grained privacy instance. |
| * @return fine-grained privacy instance |
| */ |
| public FineGrainedPrivacy getFineGrainedPrivacy(){ |
| return fineGrainedPrivacy; |
| } |
| |
| /** |
| * Return true if any of the elements has privacy level private |
| * @return true if any element has privacy level private |
| */ |
| public boolean hasPrivateElements(){ |
| if (privacyLevel == PrivacyLevel.Private) return true; |
| if ( hasFineGrainedConstraints() ){ |
| DataRange[] dataRanges = fineGrainedPrivacy.getDataRangesOfPrivacyLevel(PrivacyLevel.Private); |
| return dataRanges != null && dataRanges.length > 0; |
| } else return false; |
| } |
| |
| /** |
| * Return true if any constraints have level Private or PrivateAggregate. |
| * @return true if any constraints have level Private or PrivateAggregate |
| */ |
| public boolean hasConstraints(){ |
| if ( privacyLevel != null && |
| (privacyLevel == PrivacyLevel.Private || privacyLevel == PrivacyLevel.PrivateAggregation) ) |
| return true; |
| else if ( hasFineGrainedConstraints() ){ |
| DataRange[] privateRanges = fineGrainedPrivacy.getDataRangesOfPrivacyLevel(PrivacyLevel.Private); |
| DataRange[] aggregateRanges = fineGrainedPrivacy.getDataRangesOfPrivacyLevel(PrivacyLevel.PrivateAggregation); |
| return (privateRanges != null && privateRanges.length > 0) |
| || (aggregateRanges != null && aggregateRanges.length > 0); |
| } else return false; |
| } |
| |
| /** |
| * Get privacy constraints and put them into JSON object. |
| * @param json JSON object in which the privacy constraints are put |
| * @return JSON object including the privacy constraints |
| * @throws JSONException in case of errors in creating JSON object |
| */ |
| public JSONObject toJson(JSONObject json) throws JSONException { |
| if ( getPrivacyLevel() != null && getPrivacyLevel() != PrivacyLevel.None ) |
| json.put(DataExpression.PRIVACY, getPrivacyLevel().name()); |
| if ( hasFineGrainedConstraints() ) { |
| DataRange[] privateRanges = getFineGrainedPrivacy().getDataRangesOfPrivacyLevel(PrivacyLevel.Private); |
| JSONArray privateRangesJson = getJsonArray(privateRanges); |
| |
| DataRange[] aggregateRanges = getFineGrainedPrivacy().getDataRangesOfPrivacyLevel(PrivacyLevel.PrivateAggregation); |
| JSONArray aggregateRangesJson = getJsonArray(aggregateRanges); |
| |
| OrderedJSONObject rangesJson = new OrderedJSONObject(); |
| rangesJson.put(PrivacyLevel.Private.name(), privateRangesJson); |
| rangesJson.put(PrivacyLevel.PrivateAggregation.name(), aggregateRangesJson); |
| json.put(DataExpression.FINE_GRAINED_PRIVACY, rangesJson); |
| } |
| return json; |
| } |
| |
| private static JSONArray getJsonArray(DataRange[] ranges) throws JSONException { |
| JSONArray rangeObjects = new JSONArray(); |
| for ( DataRange range : ranges ){ |
| List<Long> rangeBegin = Arrays.stream(range.getBeginDims()).boxed().collect(Collectors.toList()); |
| List<Long> rangeEnd = Arrays.stream(range.getEndDims()).boxed().collect(Collectors.toList()); |
| JSONArray beginJson = new JSONArray(rangeBegin); |
| JSONArray endJson = new JSONArray(rangeEnd); |
| JSONArray rangeObject = new JSONArray(); |
| rangeObject.put(beginJson); |
| rangeObject.put(endJson); |
| rangeObjects.add(rangeObject); |
| } |
| return rangeObjects; |
| } |
| |
| @Override |
| public void readExternal(ObjectInput is) throws IOException { |
| this.privacyLevel = PrivacyLevel.values()[is.readInt()]; |
| int fineGrainedConstraintLength = is.readInt(); |
| if ( fineGrainedConstraintLength > 0 ){ |
| for (int i = 0; i < fineGrainedConstraintLength; i++){ |
| Integer levelIndex = (Integer) is.readInt(); |
| PrivacyLevel rangePrivacy = PrivacyLevel.values()[levelIndex]; |
| DataRange dataRange = readExternalDataRangeObject(is); |
| fineGrainedPrivacy.put(dataRange, rangePrivacy); |
| } |
| } |
| } |
| |
| @Override |
| public void writeExternal(ObjectOutput objectOutput) throws IOException { |
| objectOutput.writeInt(getPrivacyLevel().ordinal()); |
| |
| if (fineGrainedPrivacy != null && fineGrainedPrivacy.hasConstraints()){ |
| List<Entry<DataRange,PrivacyLevel>> finegrainedConstraints = fineGrainedPrivacy.getAllConstraintsList(); |
| objectOutput.writeInt(finegrainedConstraints.size()); |
| for ( Entry<DataRange,PrivacyLevel> constraint : finegrainedConstraints ) { |
| objectOutput.writeInt(constraint.getValue().ordinal()); |
| DataRange dataRange = constraint.getKey(); |
| objectOutput.writeInt(dataRange.getBeginDims().length); |
| writeExternalRangeDim(objectOutput, dataRange.getBeginDims()); |
| writeExternalRangeDim(objectOutput, dataRange.getEndDims()); |
| } |
| } |
| else { |
| objectOutput.writeInt(0); |
| } |
| } |
| |
| /** |
| * Reads a DataRange from ObjectInput. |
| * @param is ObjectInput from which the DataRange is read |
| * @return DataRange from ObjectInput |
| * @throws IOException |
| */ |
| private static DataRange readExternalDataRangeObject(ObjectInput is) throws IOException { |
| int dimLength = is.readInt(); |
| long[] beginDims = readExternalDataRangeDim(is, dimLength); |
| long[] endDims = readExternalDataRangeDim(is, dimLength); |
| return new DataRange(beginDims, endDims); |
| } |
| |
| /** |
| * Read a long array of the specified length from object input. |
| * @param is ObjectInput from which the long array is read |
| * @param dimLength length of input long array |
| * @return the input array as a long array |
| * @throws IOException |
| */ |
| private static long[] readExternalDataRangeDim(ObjectInput is, int dimLength) throws IOException { |
| long[] dims = new long[dimLength]; |
| for(int i = 0; i < dimLength; i++){ |
| dims[i] = is.readLong(); |
| } |
| return dims; |
| } |
| |
| /** |
| * Write the long array to ObjectOutput. |
| * @param objectOutput ObjectOutput in which the long array is written. |
| * @param rangeDim long array to write in ObjectOutput. |
| * @throws IOException |
| */ |
| private static void writeExternalRangeDim(ObjectOutput objectOutput, long[] rangeDim) throws IOException { |
| for ( long beginIndex : rangeDim ){ |
| objectOutput.writeLong(beginIndex); |
| } |
| } |
| |
| } |