1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18package java.security;
19
20import java.io.Serializable;
21import java.security.cert.CertPath;
22
23/**
24 * {@code CodeSigner} represents a signer of code. Instances are immutable.
25 */
26public final class CodeSigner implements Serializable {
27
28    private static final long serialVersionUID = 6819288105193937581L;
29
30    private CertPath signerCertPath;
31
32    private Timestamp timestamp;
33
34    // Cached hash code value
35    private transient int hash;
36
37    /**
38     * Constructs a new instance of {@code CodeSigner}.
39     *
40     * @param signerCertPath
41     *            the certificate path associated with this code signer.
42     * @param timestamp
43     *            the time stamp associated with this code signer, maybe {@code
44     *            null}.
45     * @throws NullPointerException
46     *             if {@code signerCertPath} is {@code null}.
47     */
48    public CodeSigner(CertPath signerCertPath, Timestamp timestamp) {
49        if (signerCertPath == null) {
50            throw new NullPointerException("signerCertPath == null");
51        }
52        this.signerCertPath = signerCertPath;
53        this.timestamp = timestamp;
54    }
55
56    /**
57     * Compares the specified object with this {@code CodeSigner} for equality.
58     * Returns {@code true} if the specified object is also an instance of
59     * {@code CodeSigner}, the two {@code CodeSigner} encapsulate the same
60     * certificate path and the same time stamp, if present in both.
61     *
62     * @param obj
63     *            object to be compared for equality with this {@code
64     *            CodeSigner}.
65     * @return {@code true} if the specified object is equal to this {@code
66     *         CodeSigner}, otherwise {@code false}.
67     */
68    @Override
69    public boolean equals(Object obj) {
70        if (obj == this) {
71            return true;
72        }
73        if (obj instanceof CodeSigner) {
74            CodeSigner that = (CodeSigner) obj;
75            if (!signerCertPath.equals(that.signerCertPath)) {
76                return false;
77            }
78            return timestamp == null ? that.timestamp == null : timestamp
79                    .equals(that.timestamp);
80        }
81        return false;
82    }
83
84    /**
85     * Returns the certificate path associated with this {@code CodeSigner}.
86     *
87     * @return the certificate path associated with this {@code CodeSigner}.
88     */
89    public CertPath getSignerCertPath() {
90        return signerCertPath;
91    }
92
93    /**
94     * Returns the time stamp associated with this {@code CodeSigner}.
95     *
96     * @return the time stamp associated with this {@code CodeSigner}, maybe
97     *         {@code null}.
98     */
99    public Timestamp getTimestamp() {
100        return timestamp;
101    }
102
103    /**
104     * Returns the hash code value for this {@code CodeSigner}. Returns the same
105     * hash code for {@code CodeSigner}s that are equal to each other as
106     * required by the general contract of {@link Object#hashCode}.
107     *
108     * @return the hash code value for this {@code CodeSigner}.
109     * @see Object#equals(Object)
110     * @see CodeSigner#equals(Object)
111     */
112    @Override
113    public int hashCode() {
114        if (hash == 0) {
115            hash = signerCertPath.hashCode()
116                    ^ (timestamp == null ? 0 : timestamp.hashCode());
117        }
118        return hash;
119    }
120
121    /**
122     * Returns a string containing a concise, human-readable description of the
123     * this {@code CodeSigner} including its first certificate and its time
124     * stamp, if present.
125     *
126     * @return a printable representation for this {@code CodeSigner}.
127     */
128    @Override
129    public String toString() {
130        // There is no any special reason for '256' here, it's taken abruptly
131        StringBuilder buf = new StringBuilder(256);
132        // The javadoc says nothing, and the others implementations behavior seems as
133        // dumping only the first certificate. Well, let's do the same.
134        buf.append("CodeSigner [").append(signerCertPath.getCertificates().get(0));
135        if( timestamp != null ) {
136            buf.append("; ").append(timestamp);
137        }
138        buf.append("]");
139        return buf.toString();
140    }
141}
142