1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase.security.visibility;
19
20 import static org.apache.hadoop.hbase.TagType.VISIBILITY_TAG_TYPE;
21 import static org.apache.hadoop.hbase.security.visibility.VisibilityConstants.LABELS_TABLE_FAMILY;
22 import static org.apache.hadoop.hbase.security.visibility.VisibilityConstants.LABELS_TABLE_NAME;
23 import static org.apache.hadoop.hbase.security.visibility.VisibilityConstants.LABEL_QUALIFIER;
24 import static org.apache.hadoop.hbase.security.visibility.VisibilityConstants.SORTED_ORDINAL_SERIALIZATION_FORMAT;
25 import static org.apache.hadoop.hbase.security.visibility.VisibilityUtils.SYSTEM_LABEL;
26
27 import java.io.ByteArrayOutputStream;
28 import java.io.DataOutputStream;
29 import java.io.IOException;
30 import java.util.ArrayList;
31 import java.util.BitSet;
32 import java.util.Collections;
33 import java.util.HashMap;
34 import java.util.HashSet;
35 import java.util.Iterator;
36 import java.util.List;
37 import java.util.Map;
38 import java.util.Set;
39 import java.util.regex.Pattern;
40
41 import org.apache.commons.logging.Log;
42 import org.apache.commons.logging.LogFactory;
43 import org.apache.hadoop.conf.Configuration;
44 import org.apache.hadoop.hbase.Cell;
45 import org.apache.hadoop.hbase.CellUtil;
46 import org.apache.hadoop.hbase.HConstants.OperationStatusCode;
47 import org.apache.hadoop.hbase.Tag;
48 import org.apache.hadoop.hbase.TagType;
49 import org.apache.hadoop.hbase.classification.InterfaceAudience;
50 import org.apache.hadoop.hbase.client.Delete;
51 import org.apache.hadoop.hbase.client.Mutation;
52 import org.apache.hadoop.hbase.client.Put;
53 import org.apache.hadoop.hbase.client.Scan;
54 import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;
55 import org.apache.hadoop.hbase.filter.Filter;
56 import org.apache.hadoop.hbase.io.util.StreamUtils;
57 import org.apache.hadoop.hbase.regionserver.HRegion;
58 import org.apache.hadoop.hbase.regionserver.OperationStatus;
59 import org.apache.hadoop.hbase.regionserver.RegionScanner;
60 import org.apache.hadoop.hbase.security.User;
61 import org.apache.hadoop.hbase.security.access.AccessControlLists;
62 import org.apache.hadoop.hbase.util.Bytes;
63 import org.apache.hadoop.hbase.util.Pair;
64 import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
65
66 @InterfaceAudience.Private
67 public class DefaultVisibilityLabelServiceImpl implements VisibilityLabelService {
68
69 private static final Log LOG = LogFactory.getLog(DefaultVisibilityLabelServiceImpl.class);
70
71
72 private static final int SYSTEM_LABEL_ORDINAL = 1;
73 private static final Tag[] LABELS_TABLE_TAGS = new Tag[1];
74 private static final byte[] DUMMY_VALUE = new byte[0];
75
76 private volatile int ordinalCounter = -1;
77 private Configuration conf;
78 private HRegion labelsRegion;
79 private VisibilityLabelsCache labelsCache;
80 private List<ScanLabelGenerator> scanLabelGenerators;
81 private List<String> superUsers;
82 private List<String> superGroups;
83
84 static {
85 ByteArrayOutputStream baos = new ByteArrayOutputStream();
86 DataOutputStream dos = new DataOutputStream(baos);
87 try {
88 StreamUtils.writeRawVInt32(dos, SYSTEM_LABEL_ORDINAL);
89 } catch (IOException e) {
90
91 }
92 LABELS_TABLE_TAGS[0] = new Tag(VISIBILITY_TAG_TYPE, baos.toByteArray());
93 }
94
95 public DefaultVisibilityLabelServiceImpl() {
96
97 }
98
99 @Override
100 public void setConf(Configuration conf) {
101 this.conf = conf;
102 }
103
104 @Override
105 public Configuration getConf() {
106 return this.conf;
107 }
108
109 @Override
110 public void init(RegionCoprocessorEnvironment e) throws IOException {
111 ZooKeeperWatcher zk = e.getRegionServerServices().getZooKeeper();
112 try {
113 labelsCache = VisibilityLabelsCache.createAndGet(zk, this.conf);
114 } catch (IOException ioe) {
115 LOG.error("Error creating VisibilityLabelsCache", ioe);
116 throw ioe;
117 }
118 this.scanLabelGenerators = VisibilityUtils.getScanLabelGenerators(this.conf);
119 Pair<List<String>, List<String>> superUsersAndGroups =
120 VisibilityUtils.getSystemAndSuperUsers(this.conf);
121 this.superUsers = superUsersAndGroups.getFirst();
122 this.superGroups = superUsersAndGroups.getSecond();
123 if (e.getRegion().getRegionInfo().getTable().equals(LABELS_TABLE_NAME)) {
124 this.labelsRegion = e.getRegion();
125 Pair<Map<String, Integer>, Map<String, List<Integer>>> labelsAndUserAuths =
126 extractLabelsAndAuths(getExistingLabelsWithAuths());
127 Map<String, Integer> labels = labelsAndUserAuths.getFirst();
128 Map<String, List<Integer>> userAuths = labelsAndUserAuths.getSecond();
129
130 addSystemLabel(this.labelsRegion, labels, userAuths);
131 int ordinal = SYSTEM_LABEL_ORDINAL;
132 for (Integer i : labels.values()) {
133 if (i > ordinal) {
134 ordinal = i;
135 }
136 }
137 this.ordinalCounter = ordinal + 1;
138 if (labels.size() > 0) {
139
140 byte[] serialized = VisibilityUtils.getDataToWriteToZooKeeper(labels);
141 this.labelsCache.writeToZookeeper(serialized, true);
142 this.labelsCache.refreshLabelsCache(serialized);
143 }
144 if (userAuths.size() > 0) {
145 byte[] serialized = VisibilityUtils.getUserAuthsDataToWriteToZooKeeper(userAuths);
146 this.labelsCache.writeToZookeeper(serialized, false);
147 this.labelsCache.refreshUserAuthsCache(serialized);
148 }
149 }
150 }
151
152 protected List<List<Cell>> getExistingLabelsWithAuths() throws IOException {
153 Scan scan = new Scan();
154 RegionScanner scanner = labelsRegion.getScanner(scan);
155 List<List<Cell>> existingLabels = new ArrayList<List<Cell>>();
156 try {
157 while (true) {
158 List<Cell> cells = new ArrayList<Cell>();
159 scanner.next(cells);
160 if (cells.isEmpty()) {
161 break;
162 }
163 existingLabels.add(cells);
164 }
165 } finally {
166 scanner.close();
167 }
168 return existingLabels;
169 }
170
171 protected Pair<Map<String, Integer>, Map<String, List<Integer>>> extractLabelsAndAuths(
172 List<List<Cell>> labelDetails) {
173 Map<String, Integer> labels = new HashMap<String, Integer>();
174 Map<String, List<Integer>> userAuths = new HashMap<String, List<Integer>>();
175 for (List<Cell> cells : labelDetails) {
176 for (Cell cell : cells) {
177 if (Bytes.equals(cell.getQualifierArray(), cell.getQualifierOffset(),
178 cell.getQualifierLength(), LABEL_QUALIFIER, 0, LABEL_QUALIFIER.length)) {
179 labels.put(
180 Bytes.toString(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength()),
181 Bytes.toInt(cell.getRowArray(), cell.getRowOffset()));
182 } else {
183
184 String user = Bytes.toString(cell.getQualifierArray(), cell.getQualifierOffset(),
185 cell.getQualifierLength());
186 List<Integer> auths = userAuths.get(user);
187 if (auths == null) {
188 auths = new ArrayList<Integer>();
189 userAuths.put(user, auths);
190 }
191 auths.add(Bytes.toInt(cell.getRowArray(), cell.getRowOffset()));
192 }
193 }
194 }
195 return new Pair<Map<String, Integer>, Map<String, List<Integer>>>(labels, userAuths);
196 }
197
198 protected void addSystemLabel(HRegion region, Map<String, Integer> labels,
199 Map<String, List<Integer>> userAuths) throws IOException {
200 if (!labels.containsKey(SYSTEM_LABEL)) {
201 Put p = new Put(Bytes.toBytes(SYSTEM_LABEL_ORDINAL));
202 p.addImmutable(LABELS_TABLE_FAMILY, LABEL_QUALIFIER, Bytes.toBytes(SYSTEM_LABEL));
203 region.put(p);
204 labels.put(SYSTEM_LABEL, SYSTEM_LABEL_ORDINAL);
205 }
206 }
207
208 @Override
209 public OperationStatus[] addLabels(List<byte[]> labels) throws IOException {
210 assert labelsRegion != null;
211 OperationStatus[] finalOpStatus = new OperationStatus[labels.size()];
212 List<Mutation> puts = new ArrayList<Mutation>(labels.size());
213 int i = 0;
214 for (byte[] label : labels) {
215 String labelStr = Bytes.toString(label);
216 if (this.labelsCache.getLabelOrdinal(labelStr) > 0) {
217 finalOpStatus[i] = new OperationStatus(OperationStatusCode.FAILURE,
218 new LabelAlreadyExistsException("Label '" + labelStr + "' already exists"));
219 } else {
220 Put p = new Put(Bytes.toBytes(ordinalCounter));
221 p.addImmutable(LABELS_TABLE_FAMILY, LABEL_QUALIFIER, label, LABELS_TABLE_TAGS);
222 if (LOG.isDebugEnabled()) {
223 LOG.debug("Adding the label " + labelStr);
224 }
225 puts.add(p);
226 ordinalCounter++;
227 }
228 i++;
229 }
230 if (mutateLabelsRegion(puts, finalOpStatus)) {
231 updateZk(true);
232 }
233 return finalOpStatus;
234 }
235
236 @Override
237 public OperationStatus[] setAuths(byte[] user, List<byte[]> authLabels) throws IOException {
238 assert labelsRegion != null;
239 OperationStatus[] finalOpStatus = new OperationStatus[authLabels.size()];
240 List<Mutation> puts = new ArrayList<Mutation>(authLabels.size());
241 int i = 0;
242 for (byte[] auth : authLabels) {
243 String authStr = Bytes.toString(auth);
244 int labelOrdinal = this.labelsCache.getLabelOrdinal(authStr);
245 if (labelOrdinal == 0) {
246
247 finalOpStatus[i] = new OperationStatus(OperationStatusCode.FAILURE,
248 new InvalidLabelException("Label '" + authStr + "' doesn't exists"));
249 } else {
250 Put p = new Put(Bytes.toBytes(labelOrdinal));
251 p.addImmutable(LABELS_TABLE_FAMILY, user, DUMMY_VALUE, LABELS_TABLE_TAGS);
252 puts.add(p);
253 }
254 i++;
255 }
256 if (mutateLabelsRegion(puts, finalOpStatus)) {
257 updateZk(false);
258 }
259 return finalOpStatus;
260 }
261
262 @Override
263 public OperationStatus[] clearAuths(byte[] user, List<byte[]> authLabels) throws IOException {
264 assert labelsRegion != null;
265 OperationStatus[] finalOpStatus = new OperationStatus[authLabels.size()];
266 List<String> currentAuths;
267 if (AccessControlLists.isGroupPrincipal(Bytes.toString(user))) {
268 String group = AccessControlLists.getGroupName(Bytes.toString(user));
269 currentAuths = this.getGroupAuths(new String[]{group}, true);
270 }
271 else {
272 currentAuths = this.getUserAuths(user, true);
273 }
274 List<Mutation> deletes = new ArrayList<Mutation>(authLabels.size());
275 int i = 0;
276 for (byte[] authLabel : authLabels) {
277 String authLabelStr = Bytes.toString(authLabel);
278 if (currentAuths.contains(authLabelStr)) {
279 int labelOrdinal = this.labelsCache.getLabelOrdinal(authLabelStr);
280 assert labelOrdinal > 0;
281 Delete d = new Delete(Bytes.toBytes(labelOrdinal));
282 d.deleteColumns(LABELS_TABLE_FAMILY, user);
283 deletes.add(d);
284 } else {
285
286 finalOpStatus[i] = new OperationStatus(OperationStatusCode.FAILURE,
287 new InvalidLabelException("Label '" + authLabelStr + "' is not set for the user "
288 + Bytes.toString(user)));
289 }
290 i++;
291 }
292 if (mutateLabelsRegion(deletes, finalOpStatus)) {
293 updateZk(false);
294 }
295 return finalOpStatus;
296 }
297
298
299
300
301
302
303
304
305
306 private boolean mutateLabelsRegion(List<Mutation> mutations, OperationStatus[] finalOpStatus)
307 throws IOException {
308 OperationStatus[] opStatus = this.labelsRegion.batchMutate(mutations
309 .toArray(new Mutation[mutations.size()]));
310 int i = 0;
311 boolean updateZk = false;
312 for (OperationStatus status : opStatus) {
313
314 updateZk = updateZk || (status.getOperationStatusCode() == OperationStatusCode.SUCCESS);
315 for (; i < finalOpStatus.length; i++) {
316 if (finalOpStatus[i] == null) {
317 finalOpStatus[i] = status;
318 break;
319 }
320 }
321 }
322 return updateZk;
323 }
324
325 @Override
326 @Deprecated
327 public List<String> getAuths(byte[] user, boolean systemCall)
328 throws IOException {
329 return getUserAuths(user, systemCall);
330 }
331
332 @Override
333 public List<String> getUserAuths(byte[] user, boolean systemCall)
334 throws IOException {
335 assert (labelsRegion != null || systemCall);
336 if (systemCall || labelsRegion == null) {
337 return this.labelsCache.getUserAuths(Bytes.toString(user));
338 }
339 Scan s = new Scan();
340 if (user != null && user.length > 0) {
341 s.addColumn(LABELS_TABLE_FAMILY, user);
342 }
343 Filter filter = VisibilityUtils.createVisibilityLabelFilter(this.labelsRegion,
344 new Authorizations(SYSTEM_LABEL));
345 s.setFilter(filter);
346 ArrayList<String> auths = new ArrayList<String>();
347 RegionScanner scanner = this.labelsRegion.getScanner(s);
348 List<Cell> results = new ArrayList<Cell>(1);
349 while (true) {
350 scanner.next(results);
351 if (results.isEmpty()) break;
352 Cell cell = results.get(0);
353 int ordinal = Bytes.toInt(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength());
354 String label = this.labelsCache.getLabel(ordinal);
355 if (label != null) {
356 auths.add(label);
357 }
358 results.clear();
359 }
360 return auths;
361 }
362
363 @Override
364 public List<String> getGroupAuths(String[] groups, boolean systemCall)
365 throws IOException {
366 assert (labelsRegion != null || systemCall);
367 if (systemCall || labelsRegion == null) {
368 return this.labelsCache.getGroupAuths(groups);
369 }
370 Scan s = new Scan();
371 if (groups != null && groups.length > 0) {
372 for (String group : groups) {
373 s.addColumn(LABELS_TABLE_FAMILY, Bytes.toBytes(AccessControlLists.toGroupEntry(group)));
374 }
375 }
376 Filter filter = VisibilityUtils.createVisibilityLabelFilter(this.labelsRegion,
377 new Authorizations(SYSTEM_LABEL));
378 s.setFilter(filter);
379 Set<String> auths = new HashSet<String>();
380 RegionScanner scanner = this.labelsRegion.getScanner(s);
381 try {
382 List<Cell> results = new ArrayList<Cell>(1);
383 while (true) {
384 scanner.next(results);
385 if (results.isEmpty()) break;
386 Cell cell = results.get(0);
387 int ordinal = Bytes.toInt(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength());
388 String label = this.labelsCache.getLabel(ordinal);
389 if (label != null) {
390 auths.add(label);
391 }
392 results.clear();
393 }
394 } finally {
395 scanner.close();
396 }
397 return new ArrayList<String>(auths);
398 }
399
400 @Override
401 public List<String> listLabels(String regex) throws IOException {
402 assert (labelsRegion != null);
403 Pair<Map<String, Integer>, Map<String, List<Integer>>> labelsAndUserAuths =
404 extractLabelsAndAuths(getExistingLabelsWithAuths());
405 Map<String, Integer> labels = labelsAndUserAuths.getFirst();
406 labels.remove(SYSTEM_LABEL);
407 if (regex != null) {
408 Pattern pattern = Pattern.compile(regex);
409 ArrayList<String> matchedLabels = new ArrayList<String>();
410 for (String label : labels.keySet()) {
411 if (pattern.matcher(label).matches()) {
412 matchedLabels.add(label);
413 }
414 }
415 return matchedLabels;
416 }
417 return new ArrayList<String>(labels.keySet());
418 }
419
420 @Override
421 public List<Tag> createVisibilityExpTags(String visExpression, boolean withSerializationFormat,
422 boolean checkAuths) throws IOException {
423 Set<Integer> auths = new HashSet<Integer>();
424 if (checkAuths) {
425 User user = VisibilityUtils.getActiveUser();
426 auths.addAll(this.labelsCache.getUserAuthsAsOrdinals(user.getShortName()));
427 auths.addAll(this.labelsCache.getGroupAuthsAsOrdinals(user.getGroupNames()));
428 }
429 return VisibilityUtils.createVisibilityExpTags(visExpression, withSerializationFormat,
430 checkAuths, auths, labelsCache);
431 }
432
433 protected void updateZk(boolean labelAddition) throws IOException {
434
435
436
437
438 Pair<Map<String, Integer>, Map<String, List<Integer>>> labelsAndUserAuths =
439 extractLabelsAndAuths(getExistingLabelsWithAuths());
440 Map<String, Integer> existingLabels = labelsAndUserAuths.getFirst();
441 Map<String, List<Integer>> userAuths = labelsAndUserAuths.getSecond();
442 if (labelAddition) {
443 byte[] serialized = VisibilityUtils.getDataToWriteToZooKeeper(existingLabels);
444 this.labelsCache.writeToZookeeper(serialized, true);
445 } else {
446 byte[] serialized = VisibilityUtils.getUserAuthsDataToWriteToZooKeeper(userAuths);
447 this.labelsCache.writeToZookeeper(serialized, false);
448 }
449 }
450
451 @Override
452 public VisibilityExpEvaluator getVisibilityExpEvaluator(Authorizations authorizations)
453 throws IOException {
454
455
456 if (isReadFromSystemAuthUser()) {
457 return new VisibilityExpEvaluator() {
458 @Override
459 public boolean evaluate(Cell cell) throws IOException {
460 return true;
461 }
462 };
463 }
464 List<String> authLabels = null;
465 for (ScanLabelGenerator scanLabelGenerator : scanLabelGenerators) {
466 try {
467
468 authLabels = scanLabelGenerator.getLabels(VisibilityUtils.getActiveUser(), authorizations);
469 authLabels = (authLabels == null) ? new ArrayList<String>() : authLabels;
470 authorizations = new Authorizations(authLabels);
471 } catch (Throwable t) {
472 LOG.error(t);
473 throw new IOException(t);
474 }
475 }
476 int labelsCount = this.labelsCache.getLabelsCount();
477 final BitSet bs = new BitSet(labelsCount + 1);
478 if (authLabels != null) {
479 for (String authLabel : authLabels) {
480 int labelOrdinal = this.labelsCache.getLabelOrdinal(authLabel);
481 if (labelOrdinal != 0) {
482 bs.set(labelOrdinal);
483 }
484 }
485 }
486
487 return new VisibilityExpEvaluator() {
488 @Override
489 public boolean evaluate(Cell cell) throws IOException {
490 boolean visibilityTagPresent = false;
491
492 if (cell.getTagsLengthUnsigned() > 0) {
493 Iterator<Tag> tagsItr = CellUtil.tagsIterator(cell.getTagsArray(), cell.getTagsOffset(),
494 cell.getTagsLengthUnsigned());
495 while (tagsItr.hasNext()) {
496 boolean includeKV = true;
497 Tag tag = tagsItr.next();
498 if (tag.getType() == VISIBILITY_TAG_TYPE) {
499 visibilityTagPresent = true;
500 int offset = tag.getTagOffset();
501 int endOffset = offset + tag.getTagLength();
502 while (offset < endOffset) {
503 Pair<Integer, Integer> result = StreamUtils
504 .readRawVarint32(tag.getBuffer(), offset);
505 int currLabelOrdinal = result.getFirst();
506 if (currLabelOrdinal < 0) {
507
508
509 int temp = -currLabelOrdinal;
510 if (bs.get(temp)) {
511 includeKV = false;
512 break;
513 }
514 } else {
515 if (!bs.get(currLabelOrdinal)) {
516 includeKV = false;
517 break;
518 }
519 }
520 offset += result.getSecond();
521 }
522 if (includeKV) {
523
524
525 return true;
526 }
527 }
528 }
529 }
530 return !(visibilityTagPresent);
531 }
532 };
533 }
534
535 protected boolean isReadFromSystemAuthUser() throws IOException {
536 User user = VisibilityUtils.getActiveUser();
537 return havingSystemAuth(user);
538 }
539
540 @Override
541 @Deprecated
542 public boolean havingSystemAuth(byte[] user) throws IOException {
543
544 if (this.superUsers.contains(Bytes.toString(user))) {
545 return true;
546 }
547 List<String> auths = this.getUserAuths(user, true);
548 if (LOG.isTraceEnabled()) {
549 LOG.trace("The auths for user " + Bytes.toString(user) + " are " + auths);
550 }
551 return auths.contains(SYSTEM_LABEL);
552 }
553
554 @Override
555 public boolean havingSystemAuth(User user) throws IOException {
556
557 if (isSystemOrSuperUser(user)) {
558 return true;
559 }
560
561 List<String> auths = this.getUserAuths(Bytes.toBytes(user.getShortName()), true);
562 if (LOG.isTraceEnabled()) {
563 LOG.trace("The auths for user " + user.getShortName() + " are " + auths);
564 }
565 if (auths.contains(SYSTEM_LABEL)) {
566 return true;
567 }
568 auths = this.getGroupAuths(user.getGroupNames(), true);
569 if (LOG.isTraceEnabled()) {
570 LOG.trace("The auths for groups of user " + user.getShortName() + " are " + auths);
571 }
572 return auths.contains(SYSTEM_LABEL);
573 }
574
575 private boolean isSystemOrSuperUser(User user) throws IOException {
576 if (this.superUsers.contains(user.getShortName())) {
577 return true;
578 }
579 String[] groups = user.getGroupNames();
580 if (groups != null && groups.length > 0) {
581 for (String group : groups) {
582 if (this.superGroups.contains(group)) {
583 return true;
584 }
585 }
586 }
587 return false;
588 }
589
590 @Override
591 public boolean matchVisibility(List<Tag> putVisTags, Byte putTagsFormat, List<Tag> deleteVisTags,
592 Byte deleteTagsFormat) throws IOException {
593 if ((deleteTagsFormat != null && deleteTagsFormat == SORTED_ORDINAL_SERIALIZATION_FORMAT)
594 && (putTagsFormat == null || putTagsFormat == SORTED_ORDINAL_SERIALIZATION_FORMAT)) {
595 if (putVisTags.size() == 0) {
596
597 return false;
598 }
599 if (putTagsFormat == null) {
600 return matchUnSortedVisibilityTags(putVisTags, deleteVisTags);
601 } else {
602 return matchOrdinalSortedVisibilityTags(putVisTags, deleteVisTags);
603 }
604 }
605 throw new IOException("Unexpected tag format passed for comparison, deleteTagsFormat : "
606 + deleteTagsFormat + ", putTagsFormat : " + putTagsFormat);
607 }
608
609
610
611
612
613
614
615 private static boolean matchUnSortedVisibilityTags(List<Tag> putVisTags,
616 List<Tag> deleteVisTags) throws IOException {
617 return compareTagsOrdinals(sortTagsBasedOnOrdinal(putVisTags),
618 sortTagsBasedOnOrdinal(deleteVisTags));
619 }
620
621
622
623
624
625
626
627 private static boolean matchOrdinalSortedVisibilityTags(List<Tag> putVisTags,
628 List<Tag> deleteVisTags) {
629 boolean matchFound = false;
630
631 if ((deleteVisTags.size()) == putVisTags.size()) {
632 for (Tag tag : deleteVisTags) {
633 matchFound = false;
634 for (Tag givenTag : putVisTags) {
635 if (Bytes.equals(tag.getBuffer(), tag.getTagOffset(), tag.getTagLength(),
636 givenTag.getBuffer(), givenTag.getTagOffset(), givenTag.getTagLength())) {
637 matchFound = true;
638 break;
639 }
640 }
641 if (!matchFound) break;
642 }
643 }
644 return matchFound;
645 }
646
647 private static List<List<Integer>> sortTagsBasedOnOrdinal(List<Tag> tags) throws IOException {
648 List<List<Integer>> fullTagsList = new ArrayList<List<Integer>>();
649 for (Tag tag : tags) {
650 if (tag.getType() == VISIBILITY_TAG_TYPE) {
651 getSortedTagOrdinals(fullTagsList, tag);
652 }
653 }
654 return fullTagsList;
655 }
656
657 private static void getSortedTagOrdinals(List<List<Integer>> fullTagsList, Tag tag)
658 throws IOException {
659 List<Integer> tagsOrdinalInSortedOrder = new ArrayList<Integer>();
660 int offset = tag.getTagOffset();
661 int endOffset = offset + tag.getTagLength();
662 while (offset < endOffset) {
663 Pair<Integer, Integer> result = StreamUtils.readRawVarint32(tag.getBuffer(), offset);
664 tagsOrdinalInSortedOrder.add(result.getFirst());
665 offset += result.getSecond();
666 }
667 Collections.sort(tagsOrdinalInSortedOrder);
668 fullTagsList.add(tagsOrdinalInSortedOrder);
669 }
670
671
672
673
674 private static boolean compareTagsOrdinals(List<List<Integer>> putVisTags,
675 List<List<Integer>> deleteVisTags) {
676 boolean matchFound = false;
677 if (deleteVisTags.size() == putVisTags.size()) {
678 for (List<Integer> deleteTagOrdinals : deleteVisTags) {
679 matchFound = false;
680 for (List<Integer> tagOrdinals : putVisTags) {
681 if (deleteTagOrdinals.equals(tagOrdinals)) {
682 matchFound = true;
683 break;
684 }
685 }
686 if (!matchFound) break;
687 }
688 }
689 return matchFound;
690 }
691
692 @Override
693 public byte[] encodeVisibilityForReplication(final List<Tag> tags, final Byte serializationFormat)
694 throws IOException {
695 if (tags.size() > 0
696 && (serializationFormat == null ||
697 serializationFormat == SORTED_ORDINAL_SERIALIZATION_FORMAT)) {
698 return createModifiedVisExpression(tags);
699 }
700 return null;
701 }
702
703
704
705
706
707
708 private byte[] createModifiedVisExpression(final List<Tag> tags)
709 throws IOException {
710 StringBuilder visibilityString = new StringBuilder();
711 for (Tag tag : tags) {
712 if (tag.getType() == TagType.VISIBILITY_TAG_TYPE) {
713 if (visibilityString.length() != 0) {
714 visibilityString.append(VisibilityConstants.CLOSED_PARAN).append(
715 VisibilityConstants.OR_OPERATOR);
716 }
717 int offset = tag.getTagOffset();
718 int endOffset = offset + tag.getTagLength();
719 boolean expressionStart = true;
720 while (offset < endOffset) {
721 Pair<Integer, Integer> result = StreamUtils.readRawVarint32(tag.getBuffer(), offset);
722 int currLabelOrdinal = result.getFirst();
723 if (currLabelOrdinal < 0) {
724 int temp = -currLabelOrdinal;
725 String label = this.labelsCache.getLabel(temp);
726 if (expressionStart) {
727
728 visibilityString.append(VisibilityConstants.OPEN_PARAN)
729 .append(VisibilityConstants.NOT_OPERATOR).append(CellVisibility.quote(label));
730 } else {
731 visibilityString.append(VisibilityConstants.AND_OPERATOR)
732 .append(VisibilityConstants.NOT_OPERATOR).append(CellVisibility.quote(label));
733 }
734 } else {
735 String label = this.labelsCache.getLabel(currLabelOrdinal);
736 if (expressionStart) {
737 visibilityString.append(VisibilityConstants.OPEN_PARAN).append(
738 CellVisibility.quote(label));
739 } else {
740 visibilityString.append(VisibilityConstants.AND_OPERATOR).append(
741 CellVisibility.quote(label));
742 }
743 }
744 expressionStart = false;
745 offset += result.getSecond();
746 }
747 }
748 }
749 if (visibilityString.length() != 0) {
750 visibilityString.append(VisibilityConstants.CLOSED_PARAN);
751
752 return Bytes.toBytes(visibilityString.toString());
753 }
754 return null;
755 }
756 }