com.microsoft.azure.storage.analytics.LogBlobIterator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of azure-storage Show documentation
Show all versions of azure-storage Show documentation
SDK for Microsoft Azure Storage Clients
/**
* Copyright Microsoft Corporation
*
* Licensed 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 com.microsoft.azure.storage.analytics;
import java.net.URISyntaxException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.EnumSet;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.TimeZone;
import com.microsoft.azure.storage.LoggingOperations;
import com.microsoft.azure.storage.OperationContext;
import com.microsoft.azure.storage.StorageException;
import com.microsoft.azure.storage.blob.BlobListingDetails;
import com.microsoft.azure.storage.blob.BlobRequestOptions;
import com.microsoft.azure.storage.blob.CloudBlob;
import com.microsoft.azure.storage.blob.CloudBlobDirectory;
import com.microsoft.azure.storage.blob.ListBlobItem;
import com.microsoft.azure.storage.core.SR;
/**
* RESERVED FOR INTERNAL USE. Provides an overlay on the LazySegmentedIterator class for enumerating Storage Analytics
* log blobs. This handles the logic for the listLogBlobs() methods found in the CloudAnalyticsClient class.
*/
class LogBlobIterator implements Iterator {
private static final String HOUR_STRING = "yyyy/MM/dd/HH";
private static final String DAY_STRING = "yyyy/MM/dd";
private static final String MONTH_STRING = "yyyy/MM";
private static final String YEAR_STRING = "yyyy";
private static final DateFormat HOUR_FORMAT = new SimpleDateFormat(HOUR_STRING);
private static final DateFormat DAY_FORMAT = new SimpleDateFormat(DAY_STRING);
private static final DateFormat MONTH_FORMAT = new SimpleDateFormat(MONTH_STRING);
private static final DateFormat YEAR_FORMAT = new SimpleDateFormat(YEAR_STRING);
private static final int HOUR_FORMAT_LENGTH = HOUR_STRING.length();
private static final int DAY_FORMAT_LENGTH = DAY_STRING.length();
private static final int MONTH_FORMAT_LENGTH = MONTH_STRING.length();
/**
* Holds a reference to the parent log CloudBlobDirectory.
*/
private final CloudBlobDirectory logDirectory;
/**
* Holds the start date and time of the log range requested.
*/
private Calendar startDate = null;
/**
* Holds the end date and time of the log range requested.
*/
private Calendar endDate = null;
/**
* Holds the value of which log types are being requested.
*/
private final EnumSet operations;
/**
* Holds the value of which blob details are being requested.
*
* Note that presently we only allow none or metadata to be specified here.
*/
private final EnumSet details;
/**
* Holds the request options to use when making the listBlob() requests.
*/
private final BlobRequestOptions options;
/**
* Holds an object used to track the execution of the operation.
*/
private final OperationContext opContext;
/**
* Holds the iterator for the current call.
*/
private Iterator currentIterator;
/**
* Represents the current time prefix being passed to listBlobs().
*/
private String currentPrefixTime = null;
/**
* Represents the prefix that marks the end
*/
private String endPrefix;
/**
* Represents whether a valid log has been already retrieved.
*/
private Boolean isItemPending = false;
/**
* Represents whether this iterator has already passed the present moment or its corresponding endTime.
*/
private Boolean isExpired = false;
/**
* The valid retrieved log that isItemPending refers to.
*/
private ListBlobItem pendingItem;
public LogBlobIterator(final CloudBlobDirectory logDirectory, final Date startDate, final Date endDate,
final EnumSet operations, final EnumSet details,
final BlobRequestOptions options, final OperationContext opContext) {
TimeZone gmtTime = TimeZone.getTimeZone("GMT");
HOUR_FORMAT.setTimeZone(gmtTime);
DAY_FORMAT.setTimeZone(gmtTime);
MONTH_FORMAT.setTimeZone(gmtTime);
YEAR_FORMAT.setTimeZone(gmtTime);
this.logDirectory = logDirectory;
this.operations = operations;
this.details = details;
this.opContext = opContext;
if (options == null) {
this.options = new BlobRequestOptions();
}
else {
this.options = options;
}
if (startDate != null) {
this.startDate = new GregorianCalendar();
this.startDate.setTime(startDate);
this.startDate.add(GregorianCalendar.MINUTE, (-this.startDate.get(GregorianCalendar.MINUTE)));
this.startDate.setTimeZone(gmtTime);
}
if (endDate != null) {
this.endDate = new GregorianCalendar();
this.endDate.setTime(endDate);
this.endDate.setTimeZone(gmtTime);
this.endPrefix = this.logDirectory.getPrefix() + HOUR_FORMAT.format(this.endDate.getTime());
}
}
@Override
public boolean hasNext() {
if (this.isItemPending) {
// Short circuit
return true;
}
try {
if (this.currentIterator == null) {
// If this is the first time, get the first iterator before entering loop.
updateIterator();
}
while (!this.isExpired) {
while (this.currentIterator.hasNext()) {
// Go through all of the logs in this iterator and see if any are of the correct type.
ListBlobItem current = this.currentIterator.next();
if (this.endDate == null || (current.getParent().getPrefix()).compareTo(this.endPrefix) <= 0) {
if (isCorrectLogType(current)) {
this.pendingItem = current;
this.isItemPending = true;
return true;
}
}
else {
// We have passed endTime
this.isExpired = true;
return false;
}
}
updateIterator();
}
}
catch (final StorageException e) {
final NoSuchElementException ex = new NoSuchElementException(SR.ENUMERATION_ERROR);
ex.initCause(e);
throw ex;
}
catch (final URISyntaxException e) {
final NoSuchElementException ex = new NoSuchElementException(SR.ENUMERATION_ERROR);
ex.initCause(e);
throw ex;
}
return false;
}
@Override
public ListBlobItem next() {
if (this.isItemPending) {
this.isItemPending = false;
return this.pendingItem;
}
if (this.hasNext()) {
return this.next();
}
else {
throw new NoSuchElementException(SR.ITERATOR_EMPTY);
}
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
/**
* Validates that the log given is of the correct log type.
*
* @param current
* the current log
* @return whether or not the log is of the correct type.
*/
private boolean isCorrectLogType(ListBlobItem current) {
HashMap metadata = ((CloudBlob) current).getMetadata();
String logType = metadata.get("LogType");
if (logType == null) {
return true;
}
if (this.operations.contains(LoggingOperations.READ) && logType.contains("read")) {
return true;
}
if (this.operations.contains(LoggingOperations.WRITE) && logType.contains("write")) {
return true;
}
if (this.operations.contains(LoggingOperations.DELETE) && logType.contains("delete")) {
return true;
}
return false;
}
/**
* Makes the next listBlob call if necessary and updates the currentIterator.
*
* @throws StorageException
* @throws URISyntaxException
*/
private void updateIterator() throws StorageException, URISyntaxException {
if (this.currentPrefixTime != null && this.currentPrefixTime.isEmpty()) {
// If we've already called listBlobs() with an empty prefix, don't do so again.
this.isExpired = true;
return;
}
GregorianCalendar now = new GregorianCalendar();
now.add(GregorianCalendar.HOUR_OF_DAY, 1);
now.setTimeZone(TimeZone.getTimeZone("GMT"));
updatePrefix();
if ((this.startDate == null || this.startDate.compareTo(now) <= 0)
&& (this.endDate == null || ((this.logDirectory.getPrefix() + this.currentPrefixTime)
.compareTo(this.endPrefix) <= 0))) {
// Only make the next call if the prefix is still possible
this.currentIterator = this.logDirectory.listBlobs(this.currentPrefixTime, true, this.details,
this.options, this.opContext).iterator();
}
else {
// We are in the future.
this.isExpired = true;
}
}
/**
* Updates the currentPrefixTime so that we can make a new call to listBlobs() with the next prefix.
*/
private void updatePrefix() {
if (this.startDate == null) {
// startDate not specified
this.currentPrefixTime = "";
}
else if (this.currentPrefixTime == null) {
// First prefix
this.currentPrefixTime = HOUR_FORMAT.format(this.startDate.getTime());
}
else if (this.currentPrefixTime.length() == HOUR_FORMAT_LENGTH) {
// Increment the hour
this.startDate.add(GregorianCalendar.HOUR_OF_DAY, 1);
if (this.startDate.get(GregorianCalendar.HOUR_OF_DAY) != 0) {
// If we are still within the same day, use the hour format
this.currentPrefixTime = HOUR_FORMAT.format(this.startDate.getTime());
}
else {
// If we've reached a day boundary, get the entire next day's logs
this.currentPrefixTime = DAY_FORMAT.format(this.startDate.getTime());
}
}
else if (this.currentPrefixTime.length() == DAY_FORMAT_LENGTH) {
// Increment the day
this.startDate.add(GregorianCalendar.DAY_OF_MONTH, 1);
if (this.startDate.get(GregorianCalendar.DAY_OF_MONTH) != 1) {
// If we are still within the same month, use the day format
this.currentPrefixTime = DAY_FORMAT.format(this.startDate.getTime());
}
else {
// If we've reached a month boundary, get the entire next month's logs
this.currentPrefixTime = MONTH_FORMAT.format(this.startDate.getTime());
}
}
else if (this.currentPrefixTime.length() == MONTH_FORMAT_LENGTH) {
// Increment the month
this.startDate.add(GregorianCalendar.MONTH, 1);
if (this.startDate.get(GregorianCalendar.MONTH) != 13) { // Undecember
// If we are still within the same year, use the month format
this.currentPrefixTime = MONTH_FORMAT.format(this.startDate.getTime());
}
else {
// If we've reached a year boundary, get the entire next year's logs
this.currentPrefixTime = YEAR_FORMAT.format(this.startDate.getTime());
}
}
else {
// Continue to increment year and get the next year's worth of logs.
this.startDate.add(GregorianCalendar.YEAR, 1);
this.currentPrefixTime = YEAR_FORMAT.format(this.startDate.getTime());
}
}
}