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