<commit_before>/**
 * Copyright (c) 2012-2014 Netflix, Inc.  All rights reserved.
 * 
 * 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.netflix.msl.msg;

import java.util.Date;

import javax.xml.bind.DatatypeConverter;

import org.json.JSONException;
import org.json.JSONObject;

import com.netflix.msl.MslConstants;
import com.netflix.msl.MslConstants.ResponseCode;
import com.netflix.msl.MslCryptoException;
import com.netflix.msl.MslEncodingException;
import com.netflix.msl.MslEntityAuthException;
import com.netflix.msl.MslError;
import com.netflix.msl.MslInternalException;
import com.netflix.msl.MslMessageException;
import com.netflix.msl.crypto.ICryptoContext;
import com.netflix.msl.entityauth.EntityAuthenticationData;
import com.netflix.msl.entityauth.EntityAuthenticationFactory;
import com.netflix.msl.entityauth.EntityAuthenticationScheme;
import com.netflix.msl.util.MslContext;

/**
 * <p>The error data is represented as
 * {@code
 * errordata = {
 *   "#mandatory" : [ "messageid", "errorcode" ],
 *   "recipient" : "string",
 *   "timestamp" : "int64(0,2^53^)",
 *   "messageid" : "int64(0,2^53^)",
 *   "errorcode" : "int32(0,-)",
 *   "internalcode" : "int32(0,-)",
 *   "errormsg" : "string",
 *   "usermsg" : "string",
 * }} where:
 * <ul>
 * <li>{@code recipient} is the intended recipient's entity identity</li>
 * <li>{@code timestamp} is the sender time when the header is created in seconds since the UNIX epoch</li>
 * <li>{@code messageid} is the message ID</li>
 * <li>{@code errorcode} is the error code</li>
 * <li>{@code internalcode} is an service-specific error code</li>
 * <li>{@code errormsg} is a developer-consumable error message</li>
 * <li>{@code usermsg} is a user-consumable localized error message</li>
 * </ul></p>
 * 
 * @author <NAME> <<EMAIL>>
 */
public class ErrorHeader extends Header {
    /** Milliseconds per second. */
    private static final long MILLISECONDS_PER_SECOND = 1000;
    
    // Message error data.
    /** JSON key recipient. */
    private static final String KEY_RECIPIENT = "recipient";
    /** JSON key timestamp. */
    private static final String KEY_TIMESTAMP = "timestamp";
    /** JSON key message ID. */
    private static final String KEY_MESSAGE_ID = "messageid";
    /** JSON key error code. */
    private static final String KEY_ERROR_CODE = "errorcode";
    /** JSON key internal code. */
    private static final String KEY_INTERNAL_CODE = "internalcode";
    /** JSON key error message. */
    private static final String KEY_ERROR_MESSAGE = "errormsg";
    /** JSON key user message. */
    private static final String KEY_USER_MESSAGE = "usermsg";
    
    /**
     * <p>Construct a new error header with the provided error data.</p>
     * 
     * <p>Headers are encrypted and signed using the crypto context appropriate
     * for the entity authentication scheme.</p>
     * 
     * @param ctx MSL context.
     * @param entityAuthData the entity authentication data.
     * @param recipient the intended recipient's entity identity. May be null.
     * @param messageId the message ID.
     * @param errorCode the error code.
     * @param internalCode the internal code. Negative to indicate no code.
     * @param errorMsg the error message. May be null.
     * @param userMsg the user message. May be null.
     * @throws MslEncodingException if there is an error encoding the JSON
     *         data.
     * @throws MslCryptoException if there is an error encrypting or signing
     *         the message.
     * @throws MslEntityAuthException if there is an error with the entity
     *         authentication data.
     * @throws MslMessageException if no entity authentication data is
     *         provided.
     */
    public ErrorHeader(final MslContext ctx, final EntityAuthenticationData entityAuthData, final String recipient, final long messageId, final ResponseCode errorCode, final int internalCode, final String errorMsg, final String userMsg) throws MslEncodingException, MslCryptoException, MslEntityAuthException, MslMessageException {
        this.entityAuthData = entityAuthData;
        this.recipient = recipient;
        this.timestamp = ctx.getTime() / MILLISECONDS_PER_SECOND;
        this.messageId = messageId;
        this.errorCode = errorCode;
        this.internalCode = (internalCode >= 0) ? internalCode : -1;
        this.errorMsg = errorMsg;
        this.userMsg = userMsg;
        
        // Message ID must be within range.
        if (this.messageId < 0 || this.messageId > MslConstants.MAX_LONG_VALUE)
            throw new MslInternalException("Message ID " + this.messageId + " is out of range.");
        
        // Message entity must be provided.
        if (entityAuthData == null)
            throw new MslMessageException(MslError.MESSAGE_ENTITY_NOT_FOUND);
        
        // Construct the JSON.
        final JSONObject errorJO = new JSONObject();
        try {
            if (this.recipient != null) errorJO.put(KEY_RECIPIENT, this.recipient);
            errorJO.put(KEY_TIMESTAMP, this.timestamp);
            errorJO.put(KEY_MESSAGE_ID, this.messageId);
            errorJO.put(KEY_ERROR_CODE, this.errorCode.intValue());
            if (this.internalCode > 0) errorJO.put(KEY_INTERNAL_CODE, this.internalCode);
            if (this.errorMsg != null) errorJO.put(KEY_ERROR_MESSAGE, this.errorMsg);
            if (this.userMsg != null) errorJO.put(KEY_USER_MESSAGE, this.userMsg);
        } catch (final JSONException e) {
            throw new MslEncodingException(MslError.JSON_ENCODE_ERROR, "errordata", e).setEntity(entityAuthData).setMessageId(messageId);
        }

        try {
            // Create the crypto context.
            final EntityAuthenticationFactory factory = ctx.getEntityAuthenticationFactory(entityAuthData.getScheme());
            final ICryptoContext cryptoContext = factory.getCryptoContext(ctx, entityAuthData);
        <commit_msg>Check for a null factory in ErrorHeader.<commit_after>/**
 * Copyright (c) 2012-2014 Netflix, Inc.  All rights reserved.
 * 
 * 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.netflix.msl.msg;

import java.util.Date;

import javax.xml.bind.DatatypeConverter;

import org.json.JSONException;
import org.json.JSONObject;

import com.netflix.msl.MslConstants;
import com.netflix.msl.MslConstants.ResponseCode;
import com.netflix.msl.MslCryptoException;
import com.netflix.msl.MslEncodingException;
import com.netflix.msl.MslEntityAuthException;
import com.netflix.msl.MslError;
import com.netflix.msl.MslInternalException;
import com.netflix.msl.MslMessageException;
import com.netflix.msl.crypto.ICryptoContext;
import com.netflix.msl.entityauth.EntityAuthenticationData;
import com.netflix.msl.entityauth.EntityAuthenticationFactory;
import com.netflix.msl.entityauth.EntityAuthenticationScheme;
import com.netflix.msl.util.MslContext;

/**
 * <p>The error data is represented as
 * {@code
 * errordata = {
 *   "#mandatory" : [ "messageid", "errorcode" ],
 *   "recipient" : "string",
 *   "timestamp" : "int64(0,2^53^)",
 *   "messageid" : "int64(0,2^53^)",
 *   "errorcode" : "int32(0,-)",
 *   "internalcode" : "int32(0,-)",
 *   "errormsg" : "string",
 *   "usermsg" : "string",
 * }} where:
 * <ul>
 * <li>{@code recipient} is the intended recipient's entity identity</li>
 * <li>{@code timestamp} is the sender time when the header is created in seconds since the UNIX epoch</li>
 * <li>{@code messageid} is the message ID</li>
 * <li>{@code errorcode} is the error code</li>
 * <li>{@code internalcode} is an service-specific error code</li>
 * <li>{@code errormsg} is a developer-consumable error message</li>
 * <li>{@code usermsg} is a user-consumable localized error message</li>
 * </ul></p>
 * 
 * @author <NAME> <<EMAIL>>
 */
public class ErrorHeader extends Header {
    /** Milliseconds per second. */
    private static final long MILLISECONDS_PER_SECOND = 1000;
    
    // Message error data.
    /** JSON key recipient. */
    private static final String KEY_RECIPIENT = "recipient";
    /** JSON key timestamp. */
    private static final String KEY_TIMESTAMP = "timestamp";
    /** JSON key message ID. */
    private static final String KEY_MESSAGE_ID = "messageid";
    /** JSON key error code. */
    private static final String KEY_ERROR_CODE = "errorcode";
    /** JSON key internal code. */
    private static final String KEY_INTERNAL_CODE = "internalcode";
    /** JSON key error message. */
    private static final String KEY_ERROR_MESSAGE = "errormsg";
    /** JSON key user message. */
    private static final String KEY_USER_MESSAGE = "usermsg";
    
    /**
     * <p>Construct a new error header with the provided error data.</p>
     * 
     * <p>Headers are encrypted and signed using the crypto context appropriate
     * for the entity authentication scheme.</p>
     * 
     * @param ctx MSL context.
     * @param entityAuthData the entity authentication data.
     * @param recipient the intended recipient's entity identity. May be null.
     * @param messageId the message ID.
     * @param errorCode the error code.
     * @param internalCode the internal code. Negative to indicate no code.
     * @param errorMsg the error message. May be null.
     * @param userMsg the user message. May be null.
     * @throws MslEncodingException if there is an error encoding the JSON
     *         data.
     * @throws MslCryptoException if there is an error encrypting or signing
     *         the message.
     * @throws MslEntityAuthException if there is an error with the entity
     *         authentication data.
     * @throws MslMessageException if no entity authentication data is
     *         provided.
     */
    public ErrorHeader(final MslContext ctx, final EntityAuthenticationData entityAuthData, final String recipient, final long messageId, final ResponseCode errorCode, final int internalCode, final String errorMsg, final String userMsg) throws MslEncodingException, MslCryptoException, MslEntityAuthException, MslMessageException {
        this.entityAuthData = entityAuthData;
        this.recipient = recipient;
        this.timestamp = ctx.getTime() / MILLISECONDS_PER_SECOND;
        this.messageId = messageId;
        this.errorCode = errorCode;
        this.internalCode = (internalCode >= 0) ? internalCode : -1;
        this.errorMsg = errorMsg;
        this.userMsg = userMsg;
        
        // Message ID must be within range.
        if (this.messageId < 0 || this.messageId > MslConstants.MAX_LONG_VALUE)
            throw new MslInternalException("Message ID " + this.messageId + " is out of range.");
        
        // Message entity must be provided.
        if (entityAuthData == null)
            throw new MslMessageException(MslError.MESSAGE_ENTITY_NOT_FOUND);
        
        // Construct the JSON.
        final JSONObject errorJO = new JSONObject();
        try {
            if (this.recipient != null) errorJO.put(KEY_RECIPIENT, this.recipient);
            errorJO.put(KEY_TIMESTAMP, this.timestamp);
            errorJO.put(KEY_MESSAGE_ID, this.messageId);
            errorJO.put(KEY_ERROR_CODE, this.errorCode.intValue());
            if (this.internalCode > 0) errorJO.put(KEY_INTERNAL_CODE, this.internalCode);
            if (this.errorMsg != null) errorJO.put(KEY_ERROR_MESSAGE, this.errorMsg);
            if (this.userMsg != null) errorJO.put(KEY_USER_MESSAGE, this.userMsg);
        } catch (final JSONException e) {
            throw new MslEncodingException(MslError.JSON_ENCODE_ERROR, "errordata", e).setEntity(entityAuthData).setMessageId(messageId);
        }

        try {
            // Create the crypto context.
            final EntityAuthenticationScheme scheme = entityAuthData.getScheme();
            final EntityAuthenticationFactory factory = ctx.getEntityAuthenticationFactory(scheme);
            if (factory == null)
                throw new MslEntityAuthException(MslError.ENTITYAUTH_FACTORY_NOT_FOUND, scheme.name());
            final ICryptoContext cryptoContext = factory.getCryptoContext(ctx, entityAuthData);
        
{'fraction_non_alphanumeric': 0.10028981086028066, 'fraction_numerical': 0.005796217205613179, 'mean_word_length': 3.215043394406943, 'pattern_counts': {'":': 0, '<': 55, '<?xml version=': 0, '>': 59, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 2}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3308448', 'n_tokens_mistral': 3742, 'n_tokens_neox': 3696, 'n_words': 1141}