source: trunk/docx4j/src/main/java/org/docx4j/openpackaging/parts/PartName.java @ 1489

Revision 1489, 21.4 KB checked in by jharrop, 13 months ago (diff)

Remove extraneous debugging

  • Property svn:eol-style set to native
Line 
1/*
2 * Copyright (c) 2006, Wygwam
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * - Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * - Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation and/or
12 * other materials provided with the distribution.
13 * - Neither the name of Wygwam nor the names of its contributors may be
14 * used to endorse or promote products derived from this software without
15 * specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28package org.docx4j.openpackaging.parts;
29
30import java.net.URI;
31import java.net.URISyntaxException;
32
33import org.apache.log4j.Logger;
34import org.docx4j.openpackaging.Base;
35import org.docx4j.openpackaging.URIHelper;
36import org.docx4j.openpackaging.exceptions.InvalidFormatException;
37import org.docx4j.openpackaging.exceptions.InvalidOperationException;
38import org.docx4j.openpackaging.exceptions.Docx4JRuntimeException;
39
40
41
42/**
43 * An immutable Open Packaging Convention compliant part name.
44 *
45 * [Docx4J comment: Note that in docx4J, part names should be resolved,
46 * before being set, so that they are absolute
47 * (ie start with '/').  In contrast, this class enforces the
48 * OPC specification, which says that a part name can't be
49 * absolute.  For this reason, you'll see the leading '/'
50 * being added and removed in various places :(              ]
51 *
52 *
53 * @author Julien Chable
54 * @version 0.1
55 */
56public final class PartName implements Comparable<PartName> {
57
58        private static Logger log = Logger.getLogger(PartName.class);   
59       
60       
61        /**
62         * Part name stored as an URI.
63         */
64        private URI partNameURI;
65
66        /*
67         * URI Characters definition (RFC 3986)
68         */
69
70        /**
71         * Reserved characters for sub delimitations.
72         */
73        private static String[] RFC3986_PCHAR_SUB_DELIMS = { "!", "$", "&", "'",
74                        "(", ")", "*", "+", ",", ";", "=" };
75
76        /**
77         * Unreserved character (+ ALPHA & DIGIT).
78         */
79        private static String[] RFC3986_PCHAR_UNRESERVED_SUP = { "-", ".", "_", "~" };
80
81        /**
82         * Authorized reserved characters for pChar.
83         */
84        private static String[] RFC3986_PCHAR_AUTHORIZED_SUP = { ":", "@" };
85
86        /**
87         * Flag to know if this part name is from a relationship part name.
88         */
89        private boolean isRelationship;
90
91        /**
92         * Constructor. Makes a ValidPartName object from a java.net.URI
93         *
94         * @param uri
95         *            The URI to validate and to transform into ValidPartName.
96         * @param checkConformance
97         *            Flag to specify if the contructor have to validate the OPC
98         *            conformance. Must be always <code>true</code> except for
99         *            special URI like '/' which is needed for internal use by
100         *            OpenXML4J but is not valid.
101         * @throws InvalidFormatException
102         *             Throw if the specified part name is not conform to Open
103         *             Packaging Convention specifications.
104         * @see java.net.URI
105         */
106        public PartName(URI uri, boolean checkConformance)
107                        throws InvalidFormatException {
108                if (checkConformance) {
109                        throwExceptionIfInvalidPartUri(uri);
110                } else {
111                        if (!URIHelper.PACKAGE_ROOT_URI.equals(uri)) {
112                                throw new Docx4JRuntimeException(
113                                                "OCP conformance must be check for ALL part name except special cases : ['/']");
114                        }
115                }
116                this.partNameURI = uri;
117                this.isRelationship = isRelationshipPartURI(this.partNameURI);
118                //log.debug( getName() + " part name created.");
119        }
120
121        /**
122         * Constructor. Makes a ValidPartName object from a String part name,
123         * provided it validates against OPC conformance.
124         *
125         * @param partName
126         *            Part name to valid and to create.
127         * @throws InvalidFormatException
128         *             Throw if the specified part name is not conform to Open
129         *             Packaging Convention specifications.
130         */
131        public PartName(String partName)
132                        throws InvalidFormatException {
133                this(partName, true);
134        }
135        /**
136         * Constructor. Makes a ValidPartName object from a String part name.
137         *
138         * @param partName
139         *            Part name to valid and to create.
140         * @param checkConformance
141         *            Flag to specify if the contructor have to validate the OPC
142         *            conformance. Must be always <code>true</code> except for
143         *            special URI like '/' which is needed for internal use by
144         *            OpenXML4J but is not valid.
145         * @throws InvalidFormatException
146         *             Throw if the specified part name is not conform to Open
147         *             Packaging Convention specifications.
148         */
149        public PartName(String partName, boolean checkConformance)
150                        throws InvalidFormatException {
151//              log.debug( "Trying to create part name " + partName);
152                URI partURI;
153                try {
154                        partURI = new URI(partName);
155                } catch (URISyntaxException e) {
156                        log.error( e.getMessage() );
157                        throw new IllegalArgumentException(
158                                        "partName argmument is not a valid OPC part name !");
159                }
160
161                if (checkConformance) {
162                        throwExceptionIfInvalidPartUri(partURI);
163                } else {
164                        if (!URIHelper.PACKAGE_ROOT_URI.equals(partURI)) {
165                                throw new Docx4JRuntimeException(
166                                                "OCP conformance must be check for ALL part name except special cases : ['/']");
167                        }
168                }
169                this.partNameURI = partURI;
170                this.isRelationship = isRelationshipPartURI(this.partNameURI);
171                //log.debug( getName() + " part name created.");
172        }
173
174        /**
175         * Check if the specified part name is a relationship part name.
176         *
177         * @param partUri
178         *            The URI to check.
179         * @return <code>true</code> if this part name respect the relationship
180         *         part naming convention else <code>false</code>.
181         */
182        private boolean isRelationshipPartURI(URI partUri) {
183                if (partUri == null)
184                        throw new IllegalArgumentException("partUri");
185
186                return partUri.getPath().matches(
187                                ".*" + URIHelper.RELATIONSHIP_PART_SEGMENT_NAME + ".*"
188                                                + URIHelper.RELATIONSHIP_PART_EXTENSION_NAME
189                                                + "$");
190        }
191
192        /**
193         * To know if this part name is a relationship part name.
194         *
195         * @return <code>true</code> if this part name respect the relationship
196         *         part naming convention else <code>false</code>.
197         */
198        public boolean isRelationshipPartURI() {
199                return this.isRelationship;
200        }
201
202        /**
203         * Throws an exception (of any kind) if the specified part name does not
204         * follow the Open Packaging Convention specifications naming rules.
205         *
206         * @param partUri
207         *            The part name to check.
208         * @throws Exception
209         *             Throws if the part name is invalid.
210         */
211        private static void throwExceptionIfInvalidPartUri(URI partUri)
212                        throws InvalidFormatException {
213                if (partUri == null)
214                        throw new IllegalArgumentException("partUri");
215                // Check if the part name URI is empty [M1.1]
216                throwExceptionIfEmptyURI(partUri);
217
218                // Check if the part name URI is absolute
219                throwExceptionIfAbsoluteUri(partUri);
220
221                // Check if the part name URI doesn't start with a forward slash [M1.4]
222                throwExceptionIfPartNameNotStartsWithForwardSlashChar(partUri);
223
224                // Check if the part name URI ends with a forward slash [M1.5]
225                throwExceptionIfPartNameEndsWithForwardSlashChar(partUri);
226
227                // Check if the part name does not have empty segments. [M1.3]
228                // Check if a segment ends with a dot ('.') character. [M1.9]
229                throwExceptionIfPartNameHaveInvalidSegments(partUri);
230        }
231
232        /**
233         * Throws an exception if the specified URI is empty. [M1.1]
234         *
235         * @param partURI
236         *            Part URI to check.
237         * @throws InvalidFormatException
238         *             If the specified URI is empty.
239         */
240        private static void throwExceptionIfEmptyURI(URI partURI)
241                        throws InvalidFormatException {
242                if (partURI == null) {
243                        throw new IllegalArgumentException("partURI");
244                }
245               
246                String uriPath = partURI.getPath();
247                if (uriPath.length() == 0
248                                || ((uriPath.length() == 1) && (uriPath.charAt(0) == URIHelper.FORWARD_SLASH_CHAR))) {
249                        throw new InvalidFormatException(
250                                        "A part name shall not be empty [M1.1]: "
251                                                        + partURI.getPath());
252                       
253                }
254        }
255
256        /**
257         * Throws an exception if the part name has empty segments. [M1.3]
258         *
259         * Throws an exception if a segment any characters other than pchar
260         * characters. [M1.6]
261         *
262         * Throws an exception if a segment contain percent-encoded forward slash
263         * ('/'), or backward slash ('\') characters. [M1.7]
264         *
265         * Throws an exception if a segment contain percent-encoded unreserved
266         * characters. [M1.8]
267         *
268         * Throws an exception if the specified part name's segments end with a dot
269         * ('.') character. [M1.9]
270         *
271         * Throws an exception if a segment doesn't include at least one non-dot
272         * character. [M1.10]
273         *
274         * @param partUri
275         *            The part name to check.
276         * @throws InvalidFormatException
277         *             if the specified URI contain an empty segments or if one the
278         *             segments contained in the part name, ends with a dot ('.')
279         *             character.
280         */
281        private static void throwExceptionIfPartNameHaveInvalidSegments(URI partUri)
282                        throws InvalidFormatException {
283                if (partUri == null || "".equals(partUri)) {
284                        throw new IllegalArgumentException("partUri");
285                }
286
287                // Split the URI into several part and analyze each
288                String[] segments = partUri.toASCIIString().split("/");
289                if (segments.length <= 1 || !segments[0].equals("")) {
290                        log.error( "" );
291                        throw new InvalidFormatException(
292                                        "A part name shall not have empty segments [M1.3]: "
293                                                        + partUri.getPath());
294                }
295                for (int i = 1; i < segments.length; ++i) {
296                        String seg = segments[i];
297                        if (seg == null || "".equals(seg)) {
298                                log.error( "" );
299                                throw new InvalidFormatException(
300                                                "A part name shall not have empty segments [M1.3]: "
301                                                                + partUri.getPath());
302                        }
303
304                        if (seg.endsWith(".")) {
305                                log.error( "" );
306                                throw new InvalidFormatException(
307                                                "A segment shall not end with a dot ('.') character [M1.9]: "
308                                                                + partUri.getPath());
309                        }
310
311                        if ("".equals(seg.replaceAll("\\\\.", ""))) {
312                                // Normally will never been invoked with the previous
313                                // implementation rule [M1.9]
314                                log.error( "" );
315                                throw new InvalidFormatException(
316                                                "A segment shall include at least one non-dot character. [M1.10]: "
317                                                                + partUri.getPath());
318                        }
319
320                        /*
321                         * Check for rule M1.6, M1.7, M1.8
322                         */
323                        checkPCharCompliance(seg);
324                }
325        }
326
327        /**
328         * Throws an exception if a segment any characters other than pchar
329         * characters. [M1.6]
330         *
331         * Throws an exception if a segment contain percent-encoded forward slash
332         * ('/'), or backward slash ('\') characters. [M1.7]
333         *
334         * Throws an exception if a segment contain percent-encoded unreserved
335         * characters. [M1.8]
336         *
337         * @param segment
338         *            The segment to check
339         */
340        private static void checkPCharCompliance(String segment)
341                        throws InvalidFormatException {
342                boolean errorFlag;
343                for (int i = 0; i < segment.length(); ++i) {
344                        char c = segment.charAt(i);
345                        errorFlag = true;
346
347                        /* Check rule M1.6 */
348
349                        // Check for digit or letter
350                        if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')
351                                        || (c >= '0' && c <= '9')) {
352                                errorFlag = false;
353                        } else {
354                                // Check "-", ".", "_", "~"
355                                for (int j = 0; j < RFC3986_PCHAR_UNRESERVED_SUP.length; ++j) {
356                                        if (c == RFC3986_PCHAR_UNRESERVED_SUP[j].charAt(0)) {
357                                                errorFlag = false;
358                                                break;
359                                        }
360                                }
361
362                                // Check ":", "@"
363                                for (int j = 0; errorFlag
364                                                && j < RFC3986_PCHAR_AUTHORIZED_SUP.length; ++j) {
365                                        if (c == RFC3986_PCHAR_AUTHORIZED_SUP[j].charAt(0)) {
366                                                errorFlag = false;
367                                        }
368                                }
369
370                                // Check "!", "$", "&", "'", "(", ")", "*", "+", ",", ";", "="
371                                for (int j = 0; errorFlag
372                                                && j < RFC3986_PCHAR_SUB_DELIMS.length; ++j) {
373                                        if (c == RFC3986_PCHAR_SUB_DELIMS[j].charAt(0)) {
374                                                errorFlag = false;
375                                        }
376                                }
377                        }
378
379                        if (errorFlag && c == '%') {
380                                // We certainly found an encoded character, check for length
381                                // now ( '%' HEXDIGIT HEXDIGIT)
382                                if (((segment.length() - i) < 2)) {
383                                        log.error( "" );
384                                        throw new InvalidFormatException("The segment " + segment
385                                                        + " contain invalid encoded character !");
386                                }
387
388                                // If not percent encoded character error occur then reset the
389                                // flag -> the character is valid
390                                errorFlag = false;
391
392                                // Decode the encoded character
393                                char decodedChar = (char) Integer.parseInt(segment.substring(
394                                                i + 1, i + 3), 16);
395                                i += 2;
396
397                                /* Check rule M1.7 */
398                                if (decodedChar == '/' || decodedChar == '\\') {
399                                        log.error( "" );
400                                        throw new InvalidFormatException(
401                                                        "A segment shall not contain percent-encoded forward slash ('/'), or backward slash ('\') characters. [M1.7]");
402                                }
403                                /* Check rule M1.8 */
404
405                                // Check for unreserved character like define in RFC3986
406                                if ((decodedChar >= 'A' && decodedChar <= 'Z')
407                                                || (decodedChar >= 'a' && decodedChar <= 'z')
408                                                || (decodedChar >= '0' && decodedChar <= '9'))
409                                        errorFlag = true;
410
411                                // Check for unreserved character "-", ".", "_", "~"
412                                for (int j = 0; !errorFlag
413                                                && j < RFC3986_PCHAR_UNRESERVED_SUP.length; ++j) {
414                                        if (c == RFC3986_PCHAR_UNRESERVED_SUP[j].charAt(0)) {
415                                                errorFlag = true;
416                                                break;
417                                        }
418                                }
419                                if (errorFlag) {
420                                        log.error( "" );
421                                        throw new InvalidFormatException(
422                                                        "A segment shall not contain percent-encoded unreserved characters. [M1.8]");
423                                        }
424                        }
425
426                        if (errorFlag) 
427                        {
428                                log.error( "" );
429                                throw new InvalidFormatException(
430                                                "A segment shall not hold any characters other than pchar characters. [M1.6]");
431                        }
432                }
433        }
434
435        /**
436         * Throws an exception if the specified part name doesn't start with a
437         * forward slash character '/'. [M1.4]
438         *
439         * @param partUri
440         *            The part name to check.
441         * @throws InvalidFormatException
442         *             If the specified part name doesn't start with a forward slash
443         *             character '/'.
444         */
445        private static void throwExceptionIfPartNameNotStartsWithForwardSlashChar(
446                        URI partUri) throws InvalidFormatException {
447                String uriPath = partUri.getPath();
448                if (uriPath.length() > 0
449                                && uriPath.charAt(0) != URIHelper.FORWARD_SLASH_CHAR)
450                {
451                        log.error( "" );
452                        throw new InvalidFormatException(
453                                        "A part name shall start with a forward slash ('/') character [M1.4]: "
454                                                        + partUri.getPath());
455                }
456        }
457
458        /**
459         * Throws an exception if the specified part name ends with a forward slash
460         * character '/'. [M1.5]
461         *
462         * @param partUri
463         *            The part name to check.
464         * @throws InvalidFormatException
465         *             If the specified part name ends with a forwar slash character
466         *             '/'.
467         */
468        private static void throwExceptionIfPartNameEndsWithForwardSlashChar(
469                        URI partUri) throws InvalidFormatException {
470                String uriPath = partUri.getPath();
471                if (uriPath.length() > 0
472                                && uriPath.charAt(uriPath.length() - 1) == URIHelper.FORWARD_SLASH_CHAR) {
473                        log.error( "" );
474                        throw new InvalidFormatException(
475                                        "A part name shall not have a forward slash as the last character [M1.5]: "
476                                                        + partUri.getPath());
477                }
478        }
479
480        /**
481         * Throws an exception if the specified URI is absolute.
482         *
483         * @param partUri
484         *            The URI to check.
485         * @throws InvalidFormatException
486         *             Throws if the specified URI is absolute.
487         */
488        private static void throwExceptionIfAbsoluteUri(URI partUri)
489                        throws InvalidFormatException {
490                if (partUri.isAbsolute()) {
491                        log.error( "" );
492                        throw new InvalidFormatException("Absolute URI forbidden: "
493                                        + partUri);
494                }
495        }
496
497        /**
498         * Compare two part name following the rule M1.12 :
499         *
500         * Part name equivalence is determined by comparing part names as
501         * case-insensitive ASCII strings. Packages shall not contain equivalent
502         * part names and package implementers shall neither create nor recognize
503         * packages with equivalent part names. [M1.12]
504         */
505        public int compareTo(PartName otherPartName) {
506                if (otherPartName == null)
507                        return -1;
508                return this.partNameURI.toASCIIString().toLowerCase().compareTo(
509                                otherPartName.partNameURI.toASCIIString().toLowerCase());
510        }
511
512        /**
513         * Retrieves the extension of the part name if any. If there is no extension
514         * returns an empty String. Example : '/document/content.xml' => 'xml'
515         *
516         * @return The extension of the part name.
517         */
518        public String getExtension() {
519                String fragment = this.partNameURI.getPath();
520                if (fragment.length() > 0) {
521                        int i = fragment.lastIndexOf(".");
522                        if (i > -1)
523                                return fragment.substring(i + 1);
524                }
525                return "";
526        }
527
528        /**
529         * Get this part name.
530         *
531         * @return The name of this part name.
532         */
533        public String getName() {
534                return this.partNameURI.toASCIIString();
535        }
536
537        /**
538         * Part name equivalence is determined by comparing part names as
539         * case-insensitive ASCII strings. Packages shall not contain equivalent
540         * part names and package implementers shall neither create nor recognize
541         * packages with equivalent part names. [M1.12]
542         */
543        @Override
544        public boolean equals(Object otherPartName) {
545                if (otherPartName == null
546                                || !(otherPartName instanceof PartName))
547                        return false;
548                return this.partNameURI.toASCIIString().toLowerCase().equals(
549                                ((PartName) otherPartName).partNameURI.toASCIIString()
550                                                .toLowerCase());
551        }
552
553        @Override
554        public int hashCode() {
555                return this.partNameURI.toASCIIString().toLowerCase().hashCode();
556        }
557
558        @Override
559        public String toString() {
560                return getName();
561        }
562
563        /* Getters and setters */
564
565        /**
566         * Part name property getter.
567         *
568         * @return This part name URI.
569         */
570        public URI getURI() {
571                return this.partNameURI;
572        }
573
574        public static String generateUniqueName(Base sourcePart, String proposedRelId,
575                        String directoryPrefix, String after_, String ext) {
576               
577                // In order to ensure unique part name,
578                // idea is to use the relId, which ought to be unique
579               
580                // Also need partName, since images for different parts are stored in a common dir
581                String sourcepartName = sourcePart.getPartName().getName();
582                int beginIndex = sourcepartName.lastIndexOf("/")+1;
583                int endIndex = sourcepartName.lastIndexOf(".");
584                String partPrefix = sourcepartName.substring(beginIndex, endIndex);
585               
586               
587                return directoryPrefix + partPrefix + "_" + after_ + "_" +  proposedRelId + "." + ext;
588        }
589       
590       
591        /** Return the path of this PartName
592         * ie up to and including its last '/',
593         * but excluding the filename segment.  */
594//      static public String base(String partName) {
595//      //              word/document.xml --->
596//      //              word/
597//                      String relationshipsPartName = null;
598//     
599//                      log.info("Splitting " + partName );
600//     
601//                      // Split partName at its last "/"
602//                      int pos = partName.lastIndexOf("/");
603//                     
604//                      return partName.substring(0, pos) + "/";
605//                     
606//              }
607
608        /**
609         *  @see URIHelper.getRelationshipPartName for Wygwam's
610         *  implementation which I only found after writing this
611         */
612        static public String getRelationshipsPartName(String partName) {
613        //              word/document.xml --->
614        //              word/_rels/document.xml.rels
615                        String relationshipsPartName = null;
616       
617//                      log.info("Splitting " + partName );
618       
619                        String rightBit = partName; 
620                       
621                        // Split partName at its last "/"
622                        int pos = partName.lastIndexOf("/");
623                        if (pos>0) {
624                                String leftBit = partName.substring(0, pos);
625                                rightBit = partName.substring(pos);
626//                              log.info("**" + leftBit + "/_rels" + rightBit + ".rels" );
627                                return leftBit + "/_rels" + rightBit + ".rels" ;
628                        } else {
629                                // eg partname: foo.ext (ie in root)
630                                if (!rightBit.startsWith("/"))
631                                        rightBit="/" + rightBit;
632//                              log.info("**" + "/_rels" + rightBit + ".rels" );
633                                return "/_rels" + rightBit + ".rels" ;                         
634                        }
635                }
636       
637        /*
638         * OpenXML4J's perhaps more robust alternative implementation
639         * of above.
640         *
641         * Build a part name where the relationship should be stored ((ex
642         * /word/document.xml -> /word/_rels/document.xml.rels)
643         *
644         * @param partUri
645         *            Source part URI
646         * @return the full path (as URI) of the relation file
647         * @throws InvalidOperationException
648         *             Throws if the specified URI is a relationshp part.
649         * @see  PartName.getRelationshipsPartName which is the
650         * implementation I use in the IO package.             
651       
652        public static PartName getRelationshipPartName(
653                        PartName partName) {
654                if (partName == null)
655                        throw new IllegalArgumentException("partName");
656
657                if (URIHelper.PACKAGE_ROOT_URI.getPath() == partName.getURI()
658                                .getPath())
659                        return URIHelper.PACKAGE_RELATIONSHIPS_ROOT_PART_NAME;
660
661                if (partName.isRelationshipPartURI())
662                        throw new InvalidOperationException("Can't be a relationship part");
663
664                String fullPath = partName.getURI().getPath();
665                String filename = getFilename(partName.getURI());
666                fullPath = fullPath.substring(0, fullPath.length() - filename.length());
667                fullPath = combine(fullPath,
668                                URIHelper.RELATIONSHIP_PART_SEGMENT_NAME);
669                fullPath = combine(fullPath, filename);
670                fullPath = fullPath
671                                + URIHelper.RELATIONSHIP_PART_EXTENSION_NAME;
672
673                PartName retPartName;
674                try {
675                        retPartName = createPartName(fullPath);
676                } catch (InvalidFormatException e) {
677                        // Should never happen in production as all data are fixed but in
678                        // case of return null:
679                        return null;
680                }
681                return retPartName;
682        }  */   
683}
Note: See TracBrowser for help on using the repository browser.