/**
* Copyright (c) Cohesive Integrations, LLC
* Copyright (c) Codice Foundation
*
* This is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, either version 3 of the License, or any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details. A copy of the GNU Lesser General Public License is distributed along with this program and can be found at
* <http://www.gnu.org/licenses/lgpl.html>.
*
**/
package net.di2e.ecdr.commons;
import java.io.IOException;
import java.io.InputStream;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.activation.MimeType;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.slf4j.LoggerFactory;
import org.slf4j.ext.XLogger;
import ddf.catalog.data.Attribute;
import ddf.catalog.data.AttributeDescriptor;
import ddf.catalog.data.BinaryContent;
import ddf.catalog.data.Metacard;
import ddf.catalog.data.MetacardType;
import ddf.catalog.data.impl.AttributeImpl;
import ddf.catalog.data.impl.MetacardTypeImpl;
public class CDRMetacard implements Metacard, Serializable {
private static final long serialVersionUID = 1L;
private transient Map<String, Attribute> map = null;
private transient Metacard wrappedMetacard;
private transient MetacardType type;
private String sourceId;
public static final String METACARD_CONTENT_COLLECTION_ATTRIBUTE = "content-collections";
public static final String RESOURCE_MIME_TYPE = "resource-mime-type";
public static final String RESOURCE_TITLE = "resource-title";
static final String THUMBNAIL_LINK = "thumbnail-link";
public static final String THUMBNAIL_LENGTH = "thumbnail-length";
public static final String THUMBNAIL_MIMETYPE = "thumbnail-mimetype";
public static final String THUMBNAIL_LINK_TITLE = "thumbnail-link-title";
static final String METADATA_LINK = "metadata-link";
public static final String WRAP_METADATA = "wrap-metadata";
private static final String THUMBNAIL_N_A = "N/A";
private static final XLogger LOGGER = new XLogger( LoggerFactory.getLogger( CDRMetacard.class ) );
/**
* Creates a {@link Metacard} with a and empty {@link Attribute}s.
*/
public CDRMetacard() {
this( CDRMetacardType.CDR_METACARD );
}
/**
* Creates a {@link Metacard} with the provided {@link MetacardType} and empty {@link Attribute} s.
*
* @param type
* the {@link MetacardType}
*/
public CDRMetacard( MetacardType mt ) {
map = new HashMap<String, Attribute>();
if ( mt != null ) {
this.type = mt;
} else {
throw new IllegalArgumentException( MetacardType.class.getName() + " instance should not be null." );
}
}
/**
* Creates a {@link Metacard} with the provided {@link Metacard}.
*
* @param metacard
* the {@link Metacard} to create this new {@code Metacard} from
*/
public CDRMetacard( Metacard metacard ) {
this( CDRMetacardType.CDR_METACARD );
if ( metacard instanceof CDRMetacard ) {
map.putAll( ((CDRMetacard) metacard).getMap() );
setSourceId( metacard.getSourceId() );
} else {
this.wrappedMetacard = metacard;
if ( metacard.getMetacardType() != null ) {
this.type = metacard.getMetacardType();
} else {
throw new IllegalArgumentException( MetacardType.class.getName() + " instance should not be null." );
}
}
}
public Map<String, Attribute> getMap() {
return map;
}
public boolean hasLocation() {
return getLocation() != null;
}
public boolean hasResource() {
return getResourceURI() != null;
}
public String getResourceMIMETypeString() {
Attribute attribute = getAttribute( RESOURCE_MIME_TYPE );
if ( attribute != null ) {
Serializable mimeType = attribute.getValue();
if ( mimeType != null && mimeType instanceof String ) {
return (String) mimeType;
}
}
return "application/unknown";
}
public long getResourceSizeLong() {
String size = getResourceSize();
if ( StringUtils.isNotBlank( size ) ) {
try {
return Long.parseLong( getResourceSize() );
} catch ( NumberFormatException e ) {
LOGGER.debug( "Could not parse resource size into integer from Metacard: " + size );
}
}
return -1;
}
public boolean hasThumbnail() {
// Order is important here especially if the original Metacard is using
// Thumbnail links and doesn't pull the thumbnail until the getThumbnail
// method is called
return getAttribute( THUMBNAIL_LINK ) != null || getThumbnail() != null;
}
public long getThumbnailLength() {
long thumbnailSize = -1;
Attribute attribute = getAttribute( THUMBNAIL_LENGTH );
if ( attribute != null ) {
thumbnailSize = (Long) attribute.getValue();
}
if ( thumbnailSize < 0 ) {
byte[] thumbnail = getThumbnail();
thumbnailSize = thumbnail == null ? -1 : thumbnail.length;
}
return thumbnailSize;
}
public String getAtomId() {
return "urn:catalog:id:" + getId();
}
public URI getMetadataURL() {
URI uri = null;
String data = requestString( METADATA_LINK );
if ( data != null ) {
try {
uri = new URI( data );
} catch ( URISyntaxException e ) {
LOGGER.warn( "failed parsing URI string, returning null" );
}
}
return uri;
}
public URI getThumbnailURL() {
URI uri = null;
String data = requestString( THUMBNAIL_LINK );
if ( data != null ) {
try {
uri = new URI( data );
} catch ( URISyntaxException e ) {
LOGGER.warn( "failed parsing URI string, returning null" );
}
}
return uri;
}
public MimeType getThumbnailMIMEType() {
Attribute attribute = getAttribute( THUMBNAIL_MIMETYPE );
if ( attribute != null ) {
return (MimeType) attribute.getValue();
}
return null;
}
public String getThumbnailLinkTitle() {
Attribute attribute = getAttribute( THUMBNAIL_LINK_TITLE );
if ( attribute != null ) {
return (String) attribute.getValue();
}
return null;
}
@Override
public String getMetadata() {
String metadata = null;
// We can't call getString here because it will get in an endless loop because of the explicit checks in
// getAttribute (for METADATA), so instead we check the values ourselves then try to pull from the link (on
// demand)
Attribute metadataAttribute = (wrappedMetacard != null) ? wrappedMetacard.getAttribute( METADATA ) : map.get( METADATA );
if ( metadataAttribute == null || StringUtils.isBlank( getAttributeValue( metadataAttribute, String.class ) ) ) {
URI metadataURI = getMetadataURL();
if ( metadataURI != null ) {
try ( InputStream in = metadataURI.toURL().openStream() ) {
metadata = IOUtils.toString( in );
if ( getAttribute( CDRMetacard.WRAP_METADATA ) != null ) {
StringBuilder sb = new StringBuilder();
sb.append( "<xml>" );
sb.append( metadata );
sb.append( "</xml>" );
metadata = sb.toString();
}
setAttribute( new AttributeImpl( Metacard.METADATA, metadata ) );
} catch ( MalformedURLException e ) {
LOGGER.warn( "Cannot read metadata due to Invalid metadata URL[" + metadataURI + "]: " + e.getMessage(), e );
} catch ( IOException e ) {
LOGGER.warn( "Could not read metadata from remote URL[" + metadataURI + "] due to: " + e.getMessage(), e );
}
}
} else {
metadata = getAttributeValue( metadataAttribute, String.class );
}
return metadata;
}
@Override
public Date getModifiedDate() {
Date modified = requestDate( Metacard.MODIFIED );
return modified == null ? new Date() : modified;
}
@Override
public String getResourceSize() {
String size = requestString( Metacard.RESOURCE_SIZE );
return StringUtils.isNotBlank( size ) && !THUMBNAIL_N_A.equalsIgnoreCase( size ) ? size : null;
}
@Override
public byte[] getThumbnail() {
byte[] thumbnail = null;
// We can't call getData here because it will get in an endless loop because of the explicit checks in
// getAttribute (for THUMBNAIL), so instead we check the values ourselves then try to pull from the link (on
// demand)
Attribute thumbnailAttribute = (wrappedMetacard != null) ? wrappedMetacard.getAttribute( THUMBNAIL ) : map.get( THUMBNAIL );
if ( thumbnailAttribute == null || getAttributeValue( thumbnailAttribute, byte[].class ) == null ) {
URI thumbnailURI = getThumbnailURL();
if ( thumbnailURI != null ) {
try ( InputStream in = thumbnailURI.toURL().openStream() ) {
thumbnail = IOUtils.toByteArray( in );
setAttribute( new AttributeImpl( Metacard.THUMBNAIL, thumbnail ) );
} catch ( MalformedURLException e ) {
LOGGER.warn( "Cannot read thumbnail due to invalid thumbnail URL[" + thumbnailURI + "]: " + e.getMessage(), e );
} catch ( IOException e ) {
LOGGER.warn( "Could not read thumbnail from remote URL[" + thumbnailURI + "] due to: " + e.getMessage(), e );
}
}
} else {
thumbnail = getAttributeValue( thumbnailAttribute, byte[].class );
}
return thumbnail;
}
@Override
public String getTitle() {
String title = requestString( Metacard.TITLE );
return title == null ? "No Title" : title;
}
@Override
public Date getCreatedDate() {
return requestDate( Metacard.CREATED );
}
/**
* Sets the date/time the {@link Metacard} was created. <br/>
* Convenience method for <code>
* {@link #setAttribute setAttribute}(new {@link AttributeImpl}({@link Metacard#CREATED}, created))
* </code>
*
* @param created
* {@link Date} when this {@link Metacard} was created.
*
* @see Metacard#CREATED
*/
public void setCreatedDate( Date created ) {
setAttribute( Metacard.CREATED, created );
}
/**
* Sets the date/time the {@link Metacard} was last modifed. <br/>
* Convenience method for <code>
* {@link #setAttribute setAttribute}(new {@link AttributeImpl}({@link Metacard#MODIFIED}, modified))
* </code>
*
* @param modified
* {@link Date} when this {@link Metacard} was last modified.
*
* @see Metacard#MODIFIED
*/
public void setModifiedDate( Date modified ) {
setAttribute( Metacard.MODIFIED, modified );
}
@Override
public Date getExpirationDate() {
return requestDate( Metacard.EXPIRATION );
}
/**
* Sets the date/time this {@link Metacard} is no longer valid and could be removed. <br/>
* Convenience method for <code>
* {@link #setAttribute setAttribute}(new {@link AttributeImpl}({@link Metacard#EXPIRATION}, expiration))
* </code>
*
* @param expiration
* {@link Date} when the {@link Metacard} expires and should be removed from any stores.
*
* @see Metacard#EXPIRATION
*/
public void setExpirationDate( Date expiration ) {
setAttribute( Metacard.EXPIRATION, expiration );
}
@Override
public Date getEffectiveDate() {
return requestDate( Metacard.EFFECTIVE );
}
/**
* Sets the date/time the {@link Metacard} was last known to be valid. <br/>
* Convenience method for <code>
* {@link #setAttribute setAttribute}(new {@link AttributeImpl}({@link Metacard#EFFECTIVE}, effective))
* </code>
*
* @param effective
* {@link Date} when the information represented by the {@link Metacard} was last known to be valid.
*
* @see Metacard#EFFECTIVE
*/
public void setEffectiveDate( Date effective ) {
setAttribute( Metacard.EFFECTIVE, effective );
}
@Override
public String getId() {
return requestString( Metacard.ID );
}
/**
* Sets the ID of the {@link Metacard}. <br/>
* Convenience method for <code>
* {@link #setAttribute setAttribute}(new {@link AttributeImpl}({@link Metacard#ID}, id))
* </code>
*
* @param id
* unique identifier of the Metacard.
*
* @see Metacard#ID
*/
public void setId( String id ) {
setAttribute( Metacard.ID, id );
}
@Override
public String getLocation() {
return requestString( Metacard.GEOGRAPHY );
}
/**
* Sets the WKT representation of the geometry. <br/>
* Convenience method for <code>
* {@link #setAttribute setAttribute}(new {@link AttributeImpl}({@link Metacard#GEOGRAPHY}, wkt))
* </code>
*
* @param wkt
* WKT-defined geospatial {@link String}, returns null if not applicable
*
* @see Metacard#GEOGRAPHY
*/
public void setLocation( String wkt ) {
setAttribute( Metacard.GEOGRAPHY, wkt );
}
@Override
public String getSourceId() {
return wrappedMetacard != null ? wrappedMetacard.getSourceId() : sourceId;
}
public void setSourceId( String id ) {
if ( wrappedMetacard != null ) {
wrappedMetacard.setSourceId( id );
} else {
this.sourceId = id;
}
}
/**
* Sets the thumbnail associated with this {@link Metacard}. <br/>
* Convenience method for <code>
* {@link #setAttribute setAttribute}(new {@link AttributeImpl}({@link Metacard#THUMBNAIL}, bytes))
* </code>
*
* @param bytes
* thumbnail for the {@link Metacard}.
*
* @see Metacard#THUMBNAIL
*/
public void setThumbnail( byte[] bytes ) {
setAttribute( Metacard.THUMBNAIL, bytes );
}
/**
* Sets the title of this {@link Metacard}. <br/>
* Convenience method for <code>
* {@link #setAttribute setAttribute}(new {@link AttributeImpl}({@link Metacard#TITLE}, id))
* </code>
*
* @param title
* Title of the {@link Metacard}
*
* @see Metacard#TITLE
*/
public void setTitle( String title ) {
setAttribute( Metacard.TITLE, title );
}
/**
* Sets the metadata associated with this {@link Metacard}. <br/>
* Convenience method for <code>
* {@link #setAttribute setAttribute}(new {@link AttributeImpl}({@link Metacard#METADATA}, metadata))
* </code>
*
* @param metadata
* Associated metadata of the {@link Metacard}
*
* @see Metacard#METADATA
*/
public void setMetadata( String metadata ) {
setAttribute( Metacard.METADATA, metadata );
}
@Override
public MetacardType getMetacardType() {
return type;
}
/**
* Sets the {@link MetacardType} of the {@link Metacard}.
*
* @param type
* {@link MetacardType} of the {@link Metacard}
*
* @see MetacardType
*/
public void setType( MetacardType mt ) {
this.type = mt;
}
@Override
public URI getContentTypeNamespace() {
URI uri = null;
String uriString = requestString( Metacard.TARGET_NAMESPACE );
if ( uriString != null && !uriString.isEmpty() ) {
uri = URI.create( uriString );
}
return uri;
}
/**
* Some types of metadata use different content types. If utilized, sets the {@link URI} of the content type. <br/>
* Convenience method for <code>
* {@link #setAttribute setAttribute}(new {@link AttributeImpl}({@link Metacard#TARGET_NAMESPACE}, targetNamespace))
* </code>
*
* @param targetNamespace
* {@link URI} of the sub-type, null if unused
*
* @see Metacard#TARGET_NAMESPACE
*/
public void setTargetNamespace( URI targetNamespace ) {
setAttribute( Metacard.TARGET_NAMESPACE, targetNamespace.toASCIIString() );
}
@Override
public String getContentTypeName() {
String content = requestString( Metacard.CONTENT_TYPE );
return StringUtils.isNotBlank( content ) ? content : "Unknown";
}
/**
* Sets the name of the content type of the {@link Metacard}. <br/>
* Convenience method for <code>
* {@link #setAttribute setAttribute}(new {@link AttributeImpl}({@link Metacard#CONTENT_TYPE}, contentType))
* </code>
*
* @param contentType
* name of content type of the {@link Metacard}
*
* @see Metacard#CONTENT_TYPE
*/
public void setContentTypeName( String contentType ) {
setAttribute( Metacard.CONTENT_TYPE, contentType );
}
@Override
public String getContentTypeVersion() {
String version = requestString( Metacard.CONTENT_TYPE_VERSION );
return StringUtils.isNotBlank( version ) ? version : "Unknown";
}
/**
* Sets the version of the content type of the {@link Metacard}. <br/>
* Convenience method for <code>
* {@link #setAttribute setAttribute}(new {@link AttributeImpl}({@link Metacard#CONTENT_TYPE_VERSION}, contentTypeVersion))
* </code>
*
* @param contentTypeVersion
* version of content type of the {@link Metacard}
*
* @see Metacard#CONTENT_TYPE_VERSION
*/
public void setContentTypeVersion( String contentTypeVersion ) {
setAttribute( Metacard.CONTENT_TYPE_VERSION, contentTypeVersion );
}
@Override
public URI getResourceURI() {
URI uri = null;
String data = requestString( Metacard.RESOURCE_URI );
if ( data != null ) {
try {
uri = new URI( data );
} catch ( URISyntaxException e ) {
LOGGER.warn( "failed parsing URI string, returning null" );
}
}
return uri;
}
/**
*
*
* @see Metacard#RESOURCE_URI
*/
public void setResourceURI( URI uri ) {
if ( uri == null ) {
return;
}
setAttribute( RESOURCE_URI, uri.toString() );
}
public void setMetadataLinkURI( URI uri ) {
if ( uri == null ) {
return;
}
setAttribute( METADATA_LINK, uri.toString() );
}
public void setThumbnailLinkURI( URI uri ) {
if ( uri == null ) {
return;
}
setAttribute( THUMBNAIL_LINK, uri.toString() );
}
/**
* Sets the size of the resource which may or may not contain a unit. <br/>
* Convenience method for <code>
* {@link #setAttribute setAttribute}(new {@link AttributeImpl}({@link Metacard#RESOURCE_SIZE}, dadSize))
* </code>
*
* @param dadSize
* {@link String} representation of the size
*
* @see Metacard#RESOURCE_SIZE
*/
public void setResourceSize( String dadSize ) {
setAttribute( RESOURCE_SIZE, dadSize );
}
/**
* Returns the security relevant markings on the {@link ddf.catalog.data.Metacard}.
*
* @return security markings
*/
public Map<String, List<String>> getSecurity() {
return requestData( Metacard.SECURITY, HashMap.class );
}
/**
* Sets the security markings on this {@link Metacard}. <br />
* Convenience method for <code>
* {@link #setAttribute setAttribute}(new {@link AttributeImpl}({@link Metacard#SECURITY}, security))
* </code>
*
* @param security
*/
public void setSecurity( HashMap<String, List<String>> security ) {
setAttribute( Metacard.SECURITY, security );
}
/**
* The brains of the operation -- does the interaction with the map or the wrapped metacard.
*
* @param <T>
* the type of the Attribute value expected
* @param attributeName
* the name of the {@link Attribute} to retrieve
* @param returnType
* the class that the value of the {@link AttributeType} is expected to be bound to
* @return the value of the requested {@link Attribute} name
*/
protected <T> T requestData( String attributeName, Class<T> returnType ) {
Attribute attribute = getAttribute( attributeName );
if ( attribute == null ) {
if ( LOGGER.isTraceEnabled() ) {
LOGGER.trace( "Attribute " + attributeName + " was not found, returning null" );
}
return null;
}
return getAttributeValue( attribute, returnType );
}
protected <T> T getAttributeValue( Attribute attribute, Class<T> returnType ) {
Serializable data = attribute.getValue();
if ( returnType.isAssignableFrom( data.getClass() ) ) {
return returnType.cast( data );
} else {
if ( LOGGER.isDebugEnabled() ) {
LOGGER.trace( data.getClass().toString() + " can not be assigned to " + returnType.toString() );
}
}
return null;
}
/**
* Get {@link Date} data from the map or wrapped metacard. <br/>
* Convenience method for <code>
* {@link #requestData requestData}(key, Date.class))
* </code>
*
* @param key
* the name of the {@link Attribute} to retrieve
* @return the value of the requested {@link Attribute} name
*
*/
protected Date requestDate( String key ) {
return requestData( key, Date.class );
}
/**
* Get {@link Double} data from the map or wrapped metacard. <br/>
* Convenience method for <code>
* {@link #requestData requestData}(key, Double.class))
* </code>
*
* @param key
* the name of the {@link Attribute} to retrieve
* @return the value of the requested {@link Attribute} name
*
*/
protected Double requestDouble( String key ) {
return requestData( key, Double.class );
}
/**
* Get {@link BinaryContent} data from the map or wrapped metacard. <br/>
* Convenience method for <code>
* {@link #requestData requestData}(key, BinaryContent.class))
* </code>
*
* @param key
* the name of the {@link Attribute} to retrieve
* @return the value of the requested {@link Attribute} name
*
*/
protected InputStream requestInputStream( String key ) {
BinaryContent data = requestData( key, BinaryContent.class );
if ( data != null ) {
return data.getInputStream();
}
return null;
}
/**
* Get {@link Integer} data from the map or wrapped metacard. <br/>
* Convenience method for <code>
* {@link #requestData requestData}(key, Integer.class))
* </code>
*
* @param key
* the name of the {@link Attribute} to retrieve
* @return the value of the requested {@link Attribute} name
*
*/
protected Integer requestInteger( String key ) {
return requestData( key, Integer.class );
}
/**
* Get {@link Long} data from the map or wrapped metacard. <br/>
* Convenience method for <code>
* {@link #requestData requestData}(key, Long.class))
* </code>
*
* @param key
* the name of the {@link Attribute} to retrieve
* @return the value of the requested {@link Attribute} name
*
*/
protected Long requestLong( String key ) {
return requestData( key, Long.class );
}
/**
* Get {@link String} data from the map or wrapped metacard. <br/>
* Convenience method for <code>
* {@link #requestData requestData}(key, String.class))
* </code>
*
* @param key
* the name of the {@link Attribute} to retrieve
* @return the value of the requested {@link Attribute} name
*
*/
protected String requestString( String key ) {
return requestData( key, String.class );
}
/**
* Get {@link byte[]} data from the map or wrapped metacard. <br/>
* Convenience method for <code>
* {@link #requestData requestData}(key, byte[].class))
* </code>
*
* @param key
* the name of the {@link Attribute} to retrieve
* @return the value of the requested {@link Attribute} name
*
*/
protected byte[] requestBytes( String key ) {
return requestData( key, byte[].class );
}
@Override
public Attribute getAttribute( String name ) {
if ( Metacard.THUMBNAIL.equals( name ) ) {
return new AttributeImpl( name, this.getThumbnail() );
} else if ( Metacard.METADATA.equals( name ) ) {
return new AttributeImpl( name, this.getMetadata() );
} else {
return (wrappedMetacard != null) ? wrappedMetacard.getAttribute( name ) : map.get( name );
}
}
/**
* Set an attribute via a name/value pair.
*
* @param name
* the name of the {@link Attribute}
* @param value
* the value of the {@link Attribute}
*/
public void setAttribute( String name, Serializable value ) {
setAttribute( new AttributeImpl( name, value ) );
}
@Override
public void setAttribute( Attribute attribute ) {
if ( attribute == null ) {
return;
}
if ( wrappedMetacard != null ) {
wrappedMetacard.setAttribute( attribute );
} else {
String name = attribute.getName();
Serializable value = attribute.getValue();
if ( name != null ) {
if ( value != null ) {
map.put( name, attribute );
} else {
map.remove( name );
}
}
}
}
private void writeObject( ObjectOutputStream stream ) throws IOException {
/*
* defaultWriteObject() is invoked for greater flexibility and compatibility. See the *Serialization Note* in
* class Javadoc.
*/
stream.defaultWriteObject();
/*
* Cannot allow unknown implementations of MetacardType to be serialized. Must convert them to our
* implementation to guarantee it is serializing the logical representation and not the physical representation.
*/
if ( type instanceof MetacardTypeImpl ) {
stream.writeObject( type );
} else {
MetacardTypeImpl mt = new MetacardTypeImpl( type.getName(), type.getAttributeDescriptors() );
stream.writeObject( mt );
}
if ( map != null ) {
stream.writeInt( map.size() );
for ( Attribute attribute : this.map.values() ) {
stream.writeObject( attribute );
}
} else {
if ( wrappedMetacard != null && wrappedMetacard.getMetacardType() != null ) {
MetacardType metacardType = wrappedMetacard.getMetacardType();
List<Attribute> attributes = new ArrayList<Attribute>();
if ( metacardType.getAttributeDescriptors() == null ) {
// no descriptors, means no attributes can be defined.
// no attributes defined, means no attributes written to
// disk
stream.writeInt( 0 );
} else {
for ( AttributeDescriptor ad : metacardType.getAttributeDescriptors() ) {
Attribute attribute = wrappedMetacard.getAttribute( ad.getName() );
if ( attribute != null ) {
attributes.add( attribute );
}
}
// Must loop again because the size of the attributes list
// is not known until list has been fully populated.
stream.writeInt( attributes.size() );
for ( Attribute attribute : attributes ) {
stream.writeObject( attribute );
}
}
}
}
}
/**
* Deserializes this instance.
*
* @param stream
* the {@link ObjectInputStream} that contains the bytes of the object
* @throws IOException
* @throws ClassNotFoundException
*/
private void readObject( ObjectInputStream stream ) throws IOException, ClassNotFoundException {
/*
* defaultReadObject() is invoked for greater flexibility and compatibility. See the *Serialization Note* in
* class Javadoc.
*/
stream.defaultReadObject();
map = new HashMap<String, Attribute>();
wrappedMetacard = null;
type = (MetacardType) stream.readObject();
if ( type == null ) {
throw new InvalidObjectException( MetacardType.class.getName() + " instance cannot be null." );
}
int numElements = stream.readInt();
for ( int i = 0; i < numElements; i++ ) {
Attribute attribute = (Attribute) stream.readObject();
if ( attribute != null ) {
AttributeDescriptor attributeDescriptor = getMetacardType().getAttributeDescriptor( attribute.getName() );
if ( attributeDescriptor != null && attribute.getValue() != null ) {
attributeDescriptor.getType().getAttributeFormat();
attributeDescriptor.getType().getClass();
}
}
setAttribute( attribute );
}
}
public int hashCode() {
return new HashCodeBuilder( 17, 37 ).append( this.getId() ).append( this.getMetacardType() ).append( this.getMetadata() ).toHashCode();
}
}